Asynchronous account authentication with Volley
Asked Answered
T

1

7

everybody.

I'm implementing an account authenticator using AbstractAccountAuthenticator and I need call an asynchronous method in the function getAuthToken, to authenticate a user. My code is like this:

public class AccountAuthenticator extends AbstractAccountAuthenticator {
    ...
    @Override
    public Bundle getAuthToken( final AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options )
        throws NetworkErrorException 
    {
        final AccountManager accountManager = AccountManager.get(context);   
        String authToken = accountManager.peekAuthToken( account, authTokenType );   
        // !!!!
        if( TextUtils.isEmpty(authToken) ) {
            <<call asynchronous method to acquire token>>
            return null;  
        }
        // !!!!
        final Bundle result = new Bundle();
        result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
        result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
        result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
        return result;
    }
    ...
}

According to Google's documentation for the 'getAuthToken' method: it returns a Bundle result or null if the result is to be returned via the response. The result will contain either:
AccountManager.KEY_INTENT, or
AccountManager.KEY_ACCOUNT_NAME, AccountManager.KEY_ACCOUNT_TYPE, and AccountManager.KEY_AUTHTOKEN, or
AccountManager.KEY_ERROR_CODE and AccountManager.KEY_ERROR_MESSAGE to indicate an error

And I need to return null because the authenticator method is asynchronous, but how I return the Bundle via the 'response' parameter, according to the documentation?
Thanks for all, and sorry my english.

Tailback answered 1/10, 2014 at 12:45 Comment(0)
T
7

Yes, I found the solution. You must use the 'response' parameter to return the results. Below is the source that I use in my application. I hope this can help.



    public Bundle getAuthToken( final AccountAuthenticatorResponse response, final Account account, String authTokenType, Bundle options )
    throws NetworkErrorException 
    {
        final Bundle result = new Bundle();
        // We will not allow authentication for a type of account not used by the service.
        if( false == authTokenType.equals(Accounts.TokenTypes.User) ) {
            result.putString( AccountManager.KEY_ERROR_MESSAGE, context.getString(R.string.error_invalid_auth_token_type) );
            return result;
        }

        final AccountManager accountManager = AccountManager.get(context);
        String authToken = accountManager.peekAuthToken( account, authTokenType );
        Token token = null;
        // If the account already has an authorization key ...
        if( ! TextUtils.isEmpty(authToken) ) 
        {
            // ...load its details from the userdata's account.
            String tokenStr = accountManager.getUserData( account, Token.class.getName() );
            JSONObject tokenJson = null;
            try {
                tokenJson = new JSONObject( tokenStr );
                token = new Token( tokenJson );
            }
            catch( JSONException e ) {
                token = new Token();
            }
        }
        // But if the key is invalid or expired ...
        if( token == null || token.isExpired() ) 
        {
            // ...loads the account user credentials to try to authenticate it.
            new SignInRequest( new Client(), account.name, accountManager.getPassword(account),
                new Response.Listener() {
                    @Override
                    public void onResponse( Token token ) {
                        /*
                        Response: a Bundle result or null if the result is to be returned via the response. 
                        The result will contain either: 
                        • AccountManager.KEY_INTENT (!!qdo envia o bundle para uma atividade!!), or 
                        • AccountManager.KEY_ACCOUNT_NAME, AccountManager.KEY_ACCOUNT_TYPE, and AccountManager.KEY_AUTHTOKEN, or 
                        • AccountManager.KEY_ERROR_CODE and AccountManager.KEY_ERROR_MESSAGE to indicate an error
                        */
                        result.putString( AccountManager.KEY_ACCOUNT_NAME, account.name );
                        result.putString( AccountManager.KEY_ACCOUNT_TYPE, account.type );
                        result.putString( AccountManager.KEY_AUTHTOKEN, token.getAccessToken() );
                        response.onResult( result );
                    }
                }
                , 
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError volleyError) {
                        int errorCode = (volleyError.networkResponse == null ? -1 : volleyError.networkResponse.statusCode);
                        String errorMessage = null;
                        if( volleyError.getLocalizedMessage() != null )
                            errorMessage = volleyError.getLocalizedMessage();
                        else if( volleyError.getMessage() != null )
                            errorMessage = volleyError.getMessage();
                        else
                            errorMessage = volleyError.toString();
                        result.putInt( AccountManager.KEY_ERROR_CODE, errorCode );
                        result.putString( AccountManager.KEY_ERROR_MESSAGE, errorMessage );
                        response.onError( errorCode, errorMessage );
                    }
                }
            ).execute( this.context );
            // Returns null because we use the response parameter. See callbacks above.
            return null;
        }
        // Otherwise, the key is valid, it returns.
        result.putString( AccountManager.KEY_ACCOUNT_NAME, account.name );
        result.putString( AccountManager.KEY_ACCOUNT_TYPE, account.type );
        result.putString( AccountManager.KEY_AUTHTOKEN, authToken );
        return result;
    }


Tailback answered 26/2, 2015 at 11:55 Comment(1)
@SanatiSharif No problem! The argument 'response' is the guy from you'll return your respost. It is used really for this, when your method can not return immediately. For example, see the lines: response.onResult(result); and response.onError(result);Tailback

© 2022 - 2024 — McMap. All rights reserved.