1

I am following the Facebook SDK Scrumptious tutorial. I successfully completed the Login and Personalize steps. Now I am stuck on the Show Me step.

When I click select friends, the list of friends is empty.

I added my brother as a Tester for the app and he clicked accept in his Facebook Developers page. Then, on Eclipse, I ran the application on his phone. But when he clicked Select friends it was still empty. It did not show my name. And when I ran the application on my phone I did not see his name in the friends list.

Does anybody know why I can't see his name on my friends list? The app works on both our phones yet the friends list is empty.

I followed the tutorial step by step.

I believe I am using the correct hashkey since the app opens on both our phones. Is there something new I am supposed to implement and Facebook just hasn't updated their tutorials?

Is it a problem with Eclipse?

MainActivity.java

public class MainActivity extends FragmentActivity  {

    private static final int SPLASH = 0;
    private static final int SELECTION = 1;
    private static final int SETTINGS = 2;
    private static final int FRAGMENT_COUNT = SETTINGS +1;

    private MenuItem settings;

    private Fragment[] fragments = new Fragment[FRAGMENT_COUNT];

    private boolean isResumed = false;

    private UiLifecycleHelper uiHelper;
    private Session.StatusCallback callback = 
        new Session.StatusCallback() {
        @Override
        public void call(Session session, 
                SessionState state, Exception exception) {
            onSessionStateChange(session, state, exception);
        }
    };

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        // only add the menu when the selection fragment is showing
        if (fragments[SELECTION].isVisible()) {
            if (menu.size() == 0) {
                settings = menu.add(R.string.settings);
            }
            return true;
        } else {
            menu.clear();
            settings = null;
        }
        return false;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.equals(settings)) {
            showFragment(SETTINGS, true);
            return true;
        }
        return false;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        uiHelper = new UiLifecycleHelper(this, callback);
        uiHelper.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        FragmentManager fm = getSupportFragmentManager();
        fragments[SPLASH] = fm.findFragmentById(R.id.splashFragment);
        fragments[SELECTION] = fm.findFragmentById(R.id.selectionFragment);
        fragments[SETTINGS] = fm.findFragmentById(R.id.userSettingsFragment);

        FragmentTransaction transaction = fm.beginTransaction();
        for(int i = 0; i < fragments.length; i++) {
            transaction.hide(fragments[i]);
        }
        transaction.commit();
    }

    private void showFragment(int fragmentIndex, boolean addToBackStack) {
        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction transaction = fm.beginTransaction();
        for (int i = 0; i < fragments.length; i++) {
            if (i == fragmentIndex) {
                transaction.show(fragments[i]);
            } else {
                transaction.hide(fragments[i]);
            }
        }
        if (addToBackStack) {
            transaction.addToBackStack(null);
        }
        transaction.commit();
    }   

    @Override
    public void onResume() {
        super.onResume();
        uiHelper.onResume();
        isResumed = true;
    }

    @Override
    public void onPause() {
        super.onPause();
        uiHelper.onPause();
        isResumed = false;
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        uiHelper.onActivityResult(requestCode, resultCode, data);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        uiHelper.onDestroy();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        uiHelper.onSaveInstanceState(outState);
    }
    private void onSessionStateChange(Session session, SessionState state, Exception exception) {
        // Only make changes if the activity is visible
        if (isResumed) {
            FragmentManager manager = getSupportFragmentManager();
            // Get the number of entries in the back stack
            int backStackSize = manager.getBackStackEntryCount();
            // Clear the back stack
            for (int i = 0; i < backStackSize; i++) {
                manager.popBackStack();
            }
            if (state.isOpened()) {
                // If the session state is open:
                // Show the authenticated fragment
                showFragment(SELECTION, false);

            } else if (state.isClosed()) {
                // If the session state is closed:
                // Show the login fragment
                showFragment(SPLASH, false);
            }
        }
    }

    @Override
    protected void onResumeFragments() {
        super.onResumeFragments();
        Session session = Session.getActiveSession();

        if (session != null && session.isOpened()) {
            // if the session is already open,
            // try to show the selection fragment
            showFragment(SELECTION, false);
        } else {
            // otherwise present the splash screen
            // and ask the person to login.
            showFragment(SPLASH, false);
        }
    }
}

SplashFragment.java

public class SplashFragment extends Fragment{

    @Override
    public View onCreateView(LayoutInflater inflater, 
            ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.splash, 
                container, false);
        return view;
    }
}

SelectionFragment.java

public class SelectionFragment extends Fragment{

    private static final String TAG = "SelectionFragment";
    private static final int REAUTH_ACTIVITY_CODE = 100;

    private ProfilePictureView profilePictureView;
    private TextView userNameView;

    private ListView listView;
    private List<BaseListElement> listElements;

    private UiLifecycleHelper uiHelper;
    private Session.StatusCallback callback = new Session.StatusCallback() {
        @Override
        public void call(final Session session, final SessionState state, final Exception exception) {
            onSessionStateChange(session, state, exception);
        }
    };

    private class ActionListAdapter extends ArrayAdapter<BaseListElement> {
        private List<BaseListElement> listElements;

        public ActionListAdapter(Context context, int resourceId, 
                                 List<BaseListElement> listElements) {
            super(context, resourceId, listElements);
            this.listElements = listElements;
            // Set up as an observer for list item changes to
            // refresh the view.
            for (int i = 0; i < listElements.size(); i++) {
                listElements.get(i).setAdapter(this);
            }
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View view = convertView;
            if (view == null) {
                LayoutInflater inflater =
                        (LayoutInflater) getActivity()
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                view = inflater.inflate(R.layout.listitem, null);
            }

            BaseListElement listElement = listElements.get(position);
            if (listElement != null) {
                view.setOnClickListener(listElement.getOnClickListener());
                ImageView icon = (ImageView) view.findViewById(R.id.icon);
                TextView text1 = (TextView) view.findViewById(R.id.text1);
                TextView text2 = (TextView) view.findViewById(R.id.text2);
                if (icon != null) {
                    icon.setImageDrawable(listElement.getIcon());
                }
                if (text1 != null) {
                    text1.setText(listElement.getText1());
                }
                if (text2 != null) {
                    text2.setText(listElement.getText2());
                }
            }
            return view;
        }

    }

    private class PeopleListElement extends BaseListElement {

        public PeopleListElement(int requestCode) {
            super(getActivity().getResources().getDrawable(R.drawable.add_friends),
                  getActivity().getResources().getString(R.string.action_people),
                  getActivity().getResources().getString(R.string.action_people_default),
                  requestCode);
        }

        @Override
        protected View.OnClickListener getOnClickListener() {
            return new View.OnClickListener() {
                @Override
                public void onClick(View view) {
//                  <del>// Do nothing for now</del>
                    startPickerActivity(PickerActivity.FRIEND_PICKER, getRequestCode());
                }
            };
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        uiHelper = new UiLifecycleHelper(getActivity(), callback);
        uiHelper.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        View view = inflater.inflate(R.layout.selection, container, false);

        // Find the user's profile picture custom view
        profilePictureView = (ProfilePictureView) view.findViewById(R.id.selection_profile_pic);
        profilePictureView.setCropped(true);

        // Find the user's name view
        userNameView = (TextView) view.findViewById(R.id.selection_user_name);

     // Find the list view
        listView = (ListView) view.findViewById(R.id.selection_list);

        // Set up the list view items, based on a list of
        // BaseListElement items
        listElements = new ArrayList<BaseListElement>();
        // Add an item for the friend picker
        listElements.add(new PeopleListElement(0));
        // Set the list view adapter
        listView.setAdapter(new ActionListAdapter(getActivity(), 
                            R.id.selection_list, listElements));

        // Check for an open session
        Session session = Session.getActiveSession();
        if (session != null && session.isOpened()) {
            // Get the user's data
            makeMeRequest(session);
        }    
        return view;
    }

    private void makeMeRequest(final Session session) {
        // Make an API call to get user data and define a 
        // new callback to handle the response.
        Request request = Request.newMeRequest(session, 
                new Request.GraphUserCallback() {
            @Override
            public void onCompleted(GraphUser user, Response response) {
                // If the response is successful
                if (session == Session.getActiveSession()) {
                    if (user != null) {
                        // Set the id for the ProfilePictureView
                        // view that in turn displays the profile picture.
                        profilePictureView.setProfileId(user.getId());
                        // Set the Textview's text to the user's name.
                        userNameView.setText(user.getName());
                    }
                }
                if (response.getError() != null) {
                    // Handle errors, will do so later.
                }
            }
        });
        request.executeAsync();
    } 

    private void onSessionStateChange(final Session session, SessionState state, Exception exception) {
        if (session != null && session.isOpened()) {
            // Get the user's data.
            makeMeRequest(session);
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REAUTH_ACTIVITY_CODE) {
          uiHelper.onActivityResult(requestCode, resultCode, data);
        } else if (resultCode == Activity.RESULT_OK) {
            // Do nothing for now
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        uiHelper.onResume();
    }

    @Override
    public void onSaveInstanceState(Bundle bundle) {
        super.onSaveInstanceState(bundle);
        uiHelper.onSaveInstanceState(bundle);
    }

    @Override
    public void onPause() {
        super.onPause();
        uiHelper.onPause();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        uiHelper.onDestroy();
    }

    private void startPickerActivity(Uri data, int requestCode) {
         Intent intent = new Intent();
         intent.setData(data);
         intent.setClass(getActivity(), PickerActivity.class);
         startActivityForResult(intent, requestCode);
     }
}

PickerActivity

public class PickerActivity extends FragmentActivity{

    public static final Uri FRIEND_PICKER = Uri.parse("picker://friend");

    private FriendPickerFragment friendPickerFragment;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.pickers);

        Bundle args = getIntent().getExtras();
        FragmentManager manager = getSupportFragmentManager();
        Fragment fragmentToShow = null;
        Uri intentUri = getIntent().getData();

        if (FRIEND_PICKER.equals(intentUri)) {
            if (savedInstanceState == null) {
                friendPickerFragment = new FriendPickerFragment(args);
            } else {
                friendPickerFragment = 
                    (FriendPickerFragment) manager.findFragmentById(R.id.picker_fragment);
            }
            // Set the listener to handle errors
            friendPickerFragment.setOnErrorListener(new PickerFragment.OnErrorListener() {
                @Override
                public void onError(PickerFragment<?> fragment,
                                    FacebookException error) {
                    PickerActivity.this.onError(error);
                }
            });
            // Set the listener to handle button clicks
            friendPickerFragment.setOnDoneButtonClickedListener(
                    new PickerFragment.OnDoneButtonClickedListener() {
                @Override
                public void onDoneButtonClicked(PickerFragment<?> fragment) {
                    finishActivity();
                }
            });
            fragmentToShow = friendPickerFragment;

        } else {
            // Nothing to do, finish
            setResult(RESULT_CANCELED);
            finish();
            return;
        }

        manager.beginTransaction()
               .replace(R.id.picker_fragment, fragmentToShow)
               .commit();
    }

    private void onError(Exception error) {
        onError(error.getLocalizedMessage(), false);
    }

    private void onError(String error, final boolean finishActivity) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(R.string.error_dialog_title).
                setMessage(error).
                setPositiveButton(R.string.error_dialog_button_text, 
                   new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        if (finishActivity) {
                            finishActivity();
                        }
                    }
                });
        builder.show();
    }

    private void finishActivity() {
        setResult(RESULT_OK, null);
        finish();
    }

    @Override
    protected void onStart() {
        super.onStart();
        if (FRIEND_PICKER.equals(getIntent().getData())) {
            try {
                friendPickerFragment.loadData(false);
            } catch (Exception ex) {
                onError(ex);
            }
        }
    }

}

EDIT logcat

01-05 13:36:45.560: D/GestureDetector(1733): [Surface Touch Event] mSweepDown False, mLRSDCnt : -1 mTouchCnt : 3 mFalseSizeCnt:0
01-05 13:36:45.710: D/ProgressBar(1733): setProgress = 0
01-05 13:36:45.710: D/ProgressBar(1733): setProgress = 0, fromUser = false
01-05 13:36:45.710: D/ProgressBar(1733): mProgress = 0mIndeterminate = false, mMin = 0, mMax = 100
01-05 13:36:45.740: D/AbsListView(1733): unregisterIRListener() is called 
01-05 13:36:45.760: D/ProgressBar(1733): updateDrawableBounds: left = 0
01-05 13:36:45.760: D/ProgressBar(1733): updateDrawableBounds: top = 3
01-05 13:36:45.760: D/ProgressBar(1733): updateDrawableBounds: right = 144
01-05 13:36:45.760: D/ProgressBar(1733): updateDrawableBounds: bottom = 147
01-05 13:36:45.890: D/AbsListView(1733): onVisibilityChanged() is called, visibility : 4
01-05 13:36:45.890: D/AbsListView(1733): unregisterIRListener() is called 
01-05 13:36:45.900: E/JavaBinder(1733): !!! FAILED BINDER TRANSACTION !!!
01-05 13:36:46.040: D/AbsListView(1733): onVisibilityChanged() is called, visibility : 0
01-05 13:36:46.040: D/AbsListView(1733): unregisterIRListener() is called 
01-05 13:36:46.040: D/AbsListView(1733): onVisibilityChanged() is called, visibility : 0
01-05 13:36:46.040: D/AbsListView(1733): unregisterIRListener() is called 
01-05 13:36:46.040: I/endeffect(1733): AbsListView.onMeasure(), getWidth()=0, getHeight()=0, this=android.widget.ListView{42460cc0 VFED.VC. .F....I. 0,0-0,0 #7f05006c app:id/selection_list}
01-05 13:36:46.070: D/dalvikvm(1733): GC_FOR_ALLOC freed 1056K, 11% free 19321K/21524K, paused 23ms, total 24ms
01-05 13:36:46.070: I/dalvikvm-heap(1733): Grow heap (frag case) to 20.170MB for 196828-byte allocation
01-05 13:36:46.090: D/dalvikvm(1733): GC_FOR_ALLOC freed 2K, 11% free 19510K/21720K, paused 20ms, total 20ms
01-05 13:36:46.140: D/dalvikvm(1733): GC_FOR_ALLOC freed 236K, 12% free 19448K/21880K, paused 22ms, total 22ms
01-05 13:36:46.140: I/dalvikvm-heap(1733): Grow heap (frag case) to 21.481MB for 1440016-byte allocation
01-05 13:36:46.170: D/dalvikvm(1733): GC_FOR_ALLOC freed <1K, 11% free 20854K/23288K, paused 29ms, total 29ms
01-05 13:36:46.180: D/AbsListView(1733): unregisterIRListener() is called 
01-05 13:36:46.180: I/endeffect(1733): AbsListView.onLayout(), getWidth()=960, getHeight()=240, this=android.widget.ListView{42460cc0 VFED.VC. .F....ID 60,270-1020,510 #7f05006c app:id/selection_list}
01-05 13:36:46.260: D/AbsListView(1733): unregisterIRListener() is called 
user2456977
  • 3,830
  • 14
  • 48
  • 87
  • Please show your codes. Any error? – Raptor Jan 05 '15 at 03:12
  • code added. no errors – user2456977 Jan 05 '15 at 03:14
  • I debugged the code and everything runs smoothly. The app simply shows an empty friends list even though my brother is a tester of the app. you have any ideas? – user2456977 Jan 05 '15 at 03:28
  • Read [this](http://stackoverflow.com/questions/23543822/facebook-friend-picker-sdk-sample-not-working-android), [this](http://stackoverflow.com/questions/25498106/why-is-my-friend-picker-fragment-empty) and [this](http://stackoverflow.com/questions/23886731/empty-facebook-friendpickerfragment). Permission issues. – Raptor Jan 05 '15 at 03:41
  • I read all those already and unfortunately still have no clue which permission issues I need to fix. You have any suggestions? My brother is a test user so he should be able to test the app. We are running it from my computer. Does he need his own hashkey? Maybe if I add the user_friends in SplashFragment that would help... – user2456977 Jan 05 '15 at 03:56
  • LogCat should tell something useful. – Raptor Jan 05 '15 at 04:01
  • i added the logcat. can't tell anything from it. any ideas? – user2456977 Jan 05 '15 at 04:19
  • The LogCat does not show anything from your App. It's more like the logs from your device. Are you sure you're in debug session? Make sure you don't filter away useful information (Hint: choose "Verbose" and filter with your App's package name; it should be done automatically by Eclipse in normal case) – Raptor Jan 05 '15 at 04:23
  • I did but it is still not working. It might just be an issue with the app configuration. I find it all very confusing – user2456977 Jan 05 '15 at 17:12
  • Hey! the logcat this time had a " !!! FAILED BINDER TRANSACTION !!!" I've seen posts with this error but not sure why it is appearing. Any help would be greatly aprpeciated - check out the updated logcat posted above. This error occured as one of the test developers. not me who is the admin – user2456977 Jan 05 '15 at 18:39
  • In [this](http://stackoverflow.com/questions/13896892/facebook-sdk-3-0-android) post, the error is said due to incorrect hash value / key. – Raptor Jan 06 '15 at 02:14
  • Solved the issue - it was a permissions issue. All I had to was add these two lines in SplashFragment.java: loginButton = (LoginButton) view.findViewById(R.id.login_button); loginButton.setReadPermissions("user_friends"); – user2456977 Jan 07 '15 at 23:29
  • Please post it as answer. – Raptor Jan 08 '15 at 01:57

1 Answers1

1

I finally solved the issue:

It was merely a permissions issue. All I had to was add these two lines in SplashFragment.java:

loginButton = (LoginButton) view.findViewById(R.id.login_button); 
loginButton.setReadPermissions("user_friends")

Facebook changed the permissions dialogue for security reasons so now you must ask the user for the "user_friends" permission to access the friends list.

I am relieved that this has nothing to do with the Failed Binder Transaction as this still appears in my application. I do not know if this effects my application in any way. Would be nice to know what it does.

user2456977
  • 3,830
  • 14
  • 48
  • 87