title: Facebook SDK 3.0 for Android without Fragments does not work
body: <p>I would like to use Facebook SDK 3.0 for Android to do some simple Graph requests. As I won't use <code>Fragment</code>s, I can't use the samples that are posted in the Facebook developer documentation.</p>
  
  <p>I had some simple <code>Activity</code>s set up already, but they did not work. I've asked questions with bounty <a href="https://stackoverflow.com/questions/13897056/when-to-request-permissions-with-facebooks-new-android-sdk-3-0">here</a> and <a href="https://stackoverflow.com/questions/14096403/facebook-login-with-android-sdk-3-0-causing-anrs-or-not-working-at-all">here</a>. But that did not really help.</p>
  
  <p>In the meantime I have been reading a lot of posts about the Facebook SDK and trying for dozens of hours, but without success. Finally, I found an additional code example on <a href="http://adilatwork.blogspot.co.uk/2013/02/facebook-android-sdk-30-requesting.html" rel="nofollow noreferrer">this blog</a>. So I've set up a complete <code>Activity</code> which is to print all friends' hometown to the LogCat.</p>
  
  <p>But this does not work, either. Instead, it asks for the basic permissions (public info + friend list) only and then quits. What am I doing wrong? The key hash, package name and class name for the Facebook app are set and there is nothing interesting printed to LogCat.</p>
  
  <pre><code>package com.my.package;
  
  import java.util.Arrays;
  import java.util.Date;
  import java.util.List;
  import org.json.JSONArray;
  import org.json.JSONObject;
  import android.app.Activity;
  import android.app.ProgressDialog;
  import android.content.Intent;
  import android.content.SharedPreferences;
  import android.os.Bundle;
  import android.preference.PreferenceManager;
  import android.widget.Toast;
  import com.facebook.*;
  
  public class FBRequest extends Activity {
  
      private static final String PERMISSION_FRIENDS_HOMETOWN = "friends_hometown";
      private static final String PREFERENCE_ACCESS_TOKEN = "facebookAccessToken";
      private static final String PREFERENCE_EXPIRATION_DATE = "facebookAccessTokenExpires";
      private ProgressDialog mProgress;
      private SharedPreferences mPrefs;
  
      private void showToast(final String text) {
          runOnUiThread(new Runnable() {
              public void run() {
                  Toast.makeText(getApplicationContext(), text, Toast.LENGTH_LONG).show();
              }
          });
      }
  
      protected void onCreate(final Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
          try {
              startFacebookRequest();
          }
          catch (Exception e) {
              e.printStackTrace();
          }
      }
  
      @Override
      public void onActivityResult(int requestCode, int resultCode, Intent data) {
          super.onActivityResult(requestCode, resultCode, data);
          Session session = Session.getActiveSession();
          if (session != null) {
              session.onActivityResult(this, requestCode, resultCode, data);
          }
      }
  
      public interface FacebookConnectHandler {
          public void onSuccess();
          public void onFailure();
      }
  
      public void startFacebookRequest() {
          connectToFacebook(new FacebookConnectHandler() {
              @Override
              public void onSuccess() {
                  // safety check
                  if (isFinishing()) { return; }
  
                  showProgressDialog("Connecting to Facebook ...");
  
                  // check for publish permissions
  
                  final List&lt;String&gt; permissions_required = Arrays.asList(PERMISSION_FRIENDS_HOMETOWN);
  
                  if (Session.getActiveSession().getPermissions() == null || !Session.getActiveSession().getPermissions().containsAll(permissions_required)) {
                      // need to make a Session.openActiveSessionFromCache(...) call
                      // because of a bug in the Facebook sdk
                      // where a second call to get permissions
                      // won't result in a session callback when the token is updated
  
                      if (Session.openActiveSessionFromCache(FBRequest.this) == null) {
                          showToast("Could not connect to Facebook! (3)");
                          return;
                      }
  
                      Session.getActiveSession().addCallback(new Session.StatusCallback() {
                          @Override
                          public void call(Session session, SessionState state, Exception exception) {
                              if (exception != null || state.equals(SessionState.CLOSED) || state.equals(SessionState.CLOSED_LOGIN_FAILED)) {
                                  // didn't get required permissions
  
                                  session.removeCallback(this);
  
                                  // safety check
                                  if (!isFinishing()) {
                                      showToast("Could not connect to Facebook! (4)");
                                  }
                              }
                              else if (state.equals(SessionState.OPENED_TOKEN_UPDATED) &amp;&amp; session.getPermissions().containsAll(permissions_required)) {
                                  // got required permissions
  
                                  session.removeCallback(this);
  
                                  // safety check
                                  if (!isFinishing()) {
                                      startFacebookRequest();
                                  }
                              }
                          }
                      });
  
                      Session.getActiveSession().requestNewReadPermissions(new Session.NewPermissionsRequest(FBRequest.this, permissions_required));
                      return;
                  }
                  startGraphRequest(Session.getActiveSession());
              }
  
  
              @Override
              public void onFailure() {
                  cancelProgressDialog();
                  showToast("Could not connect to Facebook! (1)");
              }
          });
      }
  
      private void startGraphRequest(Session session) {
          Request.executeGraphPathRequestAsync(session, "me/friends/?access_token="+session.getAccessToken()+"&amp;fields=id,name,hometown&amp;limit=500", new Request.Callback() {
              @Override
              public void onCompleted(Response response) {
                  if (response != null) {
                      try {
                          JSONArray jarr = response.getGraphObject().getInnerJSONObject().getJSONArray("data");
                          JSONObject entry;
                          StringBuilder backupStr = new StringBuilder();
                          int nExistingEntries = existingEntries.length;
                          for (int i = 0; i &lt; jarr.length(); i++) {
                              entry = jarr.getJSONObject(i);
                              if (!entry.isNull("id") &amp;&amp; !entry.isNull("name") &amp;&amp; !entry.isNull("hometown")) {
                                  System.out.println(entry.getString("hometown"));
                              }
                          }
                      }
                      catch (Exception e) {
                          e.printStackTrace();
                          showToast("Unexpected error!");
                      }
                  }
              }
          });
      }
  
      private void connectToFacebook(final FacebookConnectHandler handler) {
  
          // check whether the user already has an active session
          // and try opening it if we do
  
          // (note: making a Session.openActiveSessionFromCache(...) call
          // instead of simply checking whether the active session is opened
          // because of a bug in the Facebook sdk
          // where successive calls to update a token
          // (requesting additional permissions etc)
          // don't result in a session callback)
  
          if (Session.getActiveSession() != null &amp;&amp; Session.openActiveSessionFromCache(this) != null) {
              handler.onSuccess();
              return;
          }
  
          // initialise the session status callback
  
          Session.StatusCallback callback = new Session.StatusCallback() {
              @Override
              public void call(Session session, SessionState state, Exception exception) {
  
                  if (isFinishing()) { return; }
  
                  // check session state
  
                  if (state.equals(SessionState.CLOSED) || state.equals(SessionState.CLOSED_LOGIN_FAILED)) {
  
                      clearFacebookSharedPreferences();
  
                      // specific action for when the session is closed
                      // because an open-session request failed
                      if (state.equals(SessionState.CLOSED_LOGIN_FAILED)) {
                          cancelProgressDialog();
                          handler.onFailure();
                      }
                  }
                  else if (state.equals(SessionState.OPENED)) {
                      cancelProgressDialog();
  
                      saveFacebookSharedPreferences(session.getAccessToken(), session.getExpirationDate().getTime());
  
                      showToast("Succeeded connecting to Facebook");
  
                      handler.onSuccess();
                  }
              }
          };
  
          // make the call to open the session
  
          showProgressDialog("Connecting to Facebook...");
  
          if (Session.getActiveSession() == null &amp;&amp; mPrefs.contains(PREFERENCE_ACCESS_TOKEN) &amp;&amp; mPrefs.contains(PREFERENCE_EXPIRATION_DATE)) {
              // open a session from the access token info
              // saved in the app's shared preferences
  
              String accessTokenString = mPrefs.getString(PREFERENCE_ACCESS_TOKEN, "");
  
              Date accessTokenExpires = new Date(mPrefs.getLong(PREFERENCE_EXPIRATION_DATE, 0));
  
              AccessToken accessToken = AccessToken.createFromExistingAccessToken(accessTokenString, accessTokenExpires, null, null, null);
  
              Session.openActiveSessionWithAccessToken(this, accessToken, callback);
          }
          else {
              // open a new session, logging in if necessary
              Session.openActiveSession(this, true, callback);
          }
      }
  
      private void saveFacebookSharedPreferences(final String token, final long expiration) {
          if (mPrefs != null) {
              SharedPreferences.Editor editor = mPrefs.edit();
              editor.putString(PREFERENCE_ACCESS_TOKEN, token);
              editor.putLong(PREFERENCE_EXPIRATION_DATE, expiration);
              editor.commit();
          }
      }
  
      private void clearFacebookSharedPreferences() {
          if (mPrefs != null) {
              SharedPreferences.Editor editor = mPrefs.edit();
              editor.remove(PREFERENCE_ACCESS_TOKEN);
              editor.remove(PREFERENCE_EXPIRATION_DATE);
              editor.commit();
          }
      }
  
      private void showProgressDialog(final String text) {
          mProgress = ProgressDialog.show(getApplicationContext(), "Facebook", text, true, false);
      }
  
      private void cancelProgressDialog() {
          if (mProgress != null) {
              if (mProgress.isShowing()) {
                  mProgress.dismiss();
              }
              mProgress = null;
          }
      }
  
      @Override
      protected void onDestroy() {
          super.onDestroy();
          cancelProgressDialog();
      }
  
  }
  </code></pre>
  
  <p>Thanks in advance!</p>
  
  <p><strong>Edit:</strong> The code <em>did</em> work, but I had not called <code>setContentView()</code> and the <code>Activity</code>'s <code>finish()</code> was called in one error case. This is why one was not able to see the second request for (extended) permissions.</p>