0

I am trying to use this code:

public static Token getAccessToken(OAuth2Config oauthDetails) {
    HttpPost post = new HttpPost(oauthDetails.getTokenEndPointUrl());
    String clientId = oauthDetails.getClientId();
    String clientSecret = oauthDetails.getClientSecret();
    String scope = oauthDetails.getScope();
    List<BasicNameValuePair> parametersBody = new ArrayList<BasicNameValuePair>();
    parametersBody.add(new BasicNameValuePair(OAuthConstants.GRANT_TYPE,
            oauthDetails.getGrantType()));
    parametersBody.add(new BasicNameValuePair(OAuthConstants.USERNAME,
            oauthDetails.getUsername()));
    parametersBody.add(new BasicNameValuePair(OAuthConstants.PASSWORD,
            oauthDetails.getPassword()));
    if (isValid(clientId)) {
        parametersBody.add(new BasicNameValuePair(OAuthConstants.CLIENT_ID,
                clientId));
    }
    if (isValid(clientSecret)) {
        parametersBody.add(new BasicNameValuePair(
                OAuthConstants.CLIENT_SECRET, clientSecret));
    }
    if (isValid(scope)) {
        parametersBody.add(new BasicNameValuePair(OAuthConstants.SCOPE,
                scope));
    }
    DefaultHttpClient client = new DefaultHttpClient();
    HttpResponse response = null;
    Token accessToken = null;
    try {
        post.setEntity(new UrlEncodedFormEntity(parametersBody, HTTP.UTF_8));
        response = client.execute(post);
        int code = response.getStatusLine().getStatusCode();
        if (code >= 400) {
            Log.d(TAG, "Authorization server expects Basic authentication");
                // Add Basic Authorization header
            post.addHeader(
                    OAuthConstants.AUTHORIZATION,
                    getBasicAuthorizationHeader(oauthDetails.getUsername(),
                            oauthDetails.getPassword()));
            Log.d(TAG, "Retry with login credentials");
            try {
                response.getEntity().consumeContent();
            } catch (IOException e) {
                    // TODO Auto-generated catch block
                e.printStackTrace();
            }
            response = client.execute(post);
            code = response.getStatusLine().getStatusCode();
            if (code >= 400) {
                Log.d(TAG, "Retry with client credentials");
                post.removeHeaders(OAuthConstants.AUTHORIZATION);
                post.addHeader(
                        OAuthConstants.AUTHORIZATION,
                        getBasicAuthorizationHeader(
                                oauthDetails.getClientId(),
                                oauthDetails.getClientSecret()));
                try {
                    response.getEntity().consumeContent();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                response = client.execute(post);
                code = response.getStatusLine().getStatusCode();
                if (code >= 400) {
                    throw new RuntimeException(
                            "Could not retrieve access token for user: "
                                    + oauthDetails.getUsername());
                }
            }
        }
        Map map = handleResponse(response);
        accessToken = new Token(Long.valueOf((Integer) map.get(OAuthConstants.EXPIRES_IN)), (String) map.get(OAuthConstants.TOKEN_TYPE), (String) map.get(OAuthConstants.REFRESH_TOKEN), (String) map.get(OAuthConstants.ACCESS_TOKEN));
    } catch (ClientProtocolException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
           // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return accessToken;
}

Is part of an OAuth2Client that i am using in my Android app. I am getting this error:

android.os.NetworkOnMainThreadException

and i was reading that i should use AsyncTask, but i have no idea how to convert this method to a AsyncTask.

I will apreciate some help.

Thanks

Bozow
  • 139
  • 1
  • 15

1 Answers1

0

First of All you need a Fragment to wrap your asynctask so if the device rotates you do not create multiple requests and leak that. And also you need listener (GetAccessTokenCallbacks) to inform your activity that you have done and returning the result.

public class GetAccessTokenFragment extends Fragment {


OAuth2Config mOauthDetails;

static interface GetAccessTokenCallbacks {
  void onPostExecute(Token token);
}

private GetAccessTokenCallbacks mCallbacks;
private AccessTokenTask mTask;


@Override
public void onAttach(Activity activity) {
  super.onAttach(activity);
  mCallbacks = (GetAccessTokenCallbacks) activity;
}


@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setRetainInstance(true);
  // you must do it as follow
  // first create new instance
  // mOauthDetails = new OAuth2Config(....)
  // then use the values of MainActivity.this.mOauthDetails to initialize it


  mTask = new AccessTokenTask();
  mTask.execute();

}

@Override
public void onDetach() {
  super.onDetach();
  mCallbacks = null;
}



private class AccessTokenTask extends AsyncTask<Void, Void, Token> {

  @Override
  protected Token doInBackground(Void... param) {

    Token token = TheClassOfThisFunction.getAccessToken(mOauthDetails);
    return token;
  }

  @Override
  protected void onPostExecute(Token token) {
    if (mCallbacks != null) {
      mCallbacks.onPostExecute(token[0]);
    }
  }
 }
}

and in your MainActivity you must implement GetAccessTokenFragment.GetAccessTokenCallbacks and creating the GetAccessTokenFragment.

public class MainActivity extends FragmentActivity implements GetAccessTokenFragment.GetAccessTokenCallbacks {

      public OAuth2Config mOauthDetails;

      private static final String TAG_GetAccessTokenFragment = "GetAccessToken";

      private GetAccessTokenFragment mGetAccessTokenFragment;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        // Initialize mOauthDetails here


        FragmentManager fm = getSupportFragmentManager();
        mGetAccessTokenFragment = (GetAccessTokenFragment) fm.findFragmentByTag(TAG_GetAccessTokenFragment);

        if (mGetAccessTokenFragment == null) {
          mGetAccessTokenFragment = new GetAccessTokenFragment();
          fm.beginTransaction().add(mGetAccessTokenFragment, TAG_GetAccessTokenFragment).commit();
        }

      }

      @Override
      public void onPostExecute(Token token) {
          //you got your token here
      }
    }

Seems that OAuthConfig is called in the following:

public class OAuth2Client {
private final String username;
private final String password;
private final String clientId;
private final String clientSecret;
private final String site;
public OAuth2Client(String username, String password, String clientId, String clientSecret, String site) {
    this.username = username;
    this.password = password;
    this.clientId = clientId;
    this.clientSecret = clientSecret;
    this.site = site;
}
public String getUsername() {
    return username;
}
public String getPassword() {
    return password;
}
public String getClientId() {
    return clientId;
}
public String getClientSecret() {
    return clientSecret;
}
public String getSite() {
    return site;
}
public Token getAccessToken() {
    OAuth2Config oauthConfig = new OAuth2Config.OAuth2ConfigBuilder(username, password, clientId, clientSecret, site)
            .grantType("password").build();
    return OAuthUtils.getAccessToken(oauthConfig);
}

}

Bozow
  • 139
  • 1
  • 15
mmlooloo
  • 18,937
  • 5
  • 45
  • 64
  • My application has only 2 activities with containers for fragments, basically my app handles fragments all the time. When user press log in button, there comes a fragment called LogInFragment where user will input username and password. when user confirms username and password it calls a Dialog Fragment that just shows Login in... and there is where all the log in progress is done. – Bozow Oct 24 '14 at 06:30
  • I guess i got it, i will test it now. Basically the method i have to get the accessToken does not need to be an asyncTask but i should execute that method in the AsyncTask. did i understand it right? – Bozow Oct 24 '14 at 06:46
  • Exactly, and my code just do that for you, I put your `getAccessToken` in `doInBackground` and because `doInBackground` runs on other thread (worker thread) you will get ride of that exception. because user can rotate your device and this cause another call to `getAccessToken` which I think it is not necessary I put AsyncTask into a retained fragment to just request one time. – mmlooloo Oct 24 '14 at 06:56
  • this line complains: mCallbacks.onPostExecute(token[0]); Array typed expected, found: com.xxxxxx.xxxxx.xxxxx.Token – Bozow Oct 24 '14 at 07:29
  • ok, i will explain how my app works: There is an Activity, used only as a container for the fragments. From LogInFragment i get username and password that i pass as arguments to the DialogFragment where the validation and token should be implemented. I should initialize the OAuth2Client with all parameters and then call the getAccessToken. if i get token, storage in share preferences and go to the next activity witch will contain a new different fragment. – Bozow Oct 24 '14 at 07:44
  • So far i think is working. if i enter wrong user and password, is crashing, but if i enter correct ones is working. Thanks a lot. – Bozow Oct 24 '14 at 08:31
  • Sorry I can not help you right now, I have to deliver a lot of work just this Monday and I can not debug it, sorry but If you have any problem ask I will look at it when find some free time. – mmlooloo Oct 24 '14 at 08:36
  • Do you know how i can use this inside a Dialog Fragment? of course i do have an Activity but is just the container for all the fragments. instead of creating a fragment, create a DialogFragment with layout Login in... (I did implement already). and to get the onPostExecute(token) in the Dialog fragment, not in the activity. – Bozow Oct 27 '14 at 09:25
  • 1
    the first `protected void onPostExecute(Token token)` delivers the result to the fragment, I think you can replace that fragment by DialogFragment but I am not sure that DialogFragment retains its state during configuration change or not, so read this [post](http://stackoverflow.com/questions/11307390/dialogfragment-disappears-on-rotation-despite-setretaininstancetrue) so delete `setRetainInstance(true);` – mmlooloo Oct 27 '14 at 09:38