Balkyto
Balkyto

Reputation: 1510

Android FB API 3.0 - set permissions only once

I'm trying to figure out how new API works, so I've managed to understand the concept, and managed to do my own "hello world", that log on to facebook, log out and try to upload image.

Now in both HelloFacebookSample and SessionLoginSimple, there is a simple login to facebook, and in the HelloFacebookSample, when you click "Post photo", a new dialog for login appears, because the permissions are not set.

this is the code from HelloFacebookSample:

 private void performPublish(PendingAction action) {
    Session session = Session.getActiveSession();
    if (session != null) {
        pendingAction = action;
        if (session.getPermissions().contains("publish_actions")) {
            // We can do the action right away.
            handlePendingAction();
        } else {
            // We need to reauthorize, then complete the action when we get called back.
            Session.ReauthorizeRequest reauthRequest = new Session.ReauthorizeRequest(this, PERMISSIONS).
                    setRequestCode(REAUTHORIZE_ACTIVITY).
                    setLoginBehavior(SessionLoginBehavior.SSO_WITH_FALLBACK);
            session.reauthorizeForPublish(reauthRequest);
        }
    }
}

So as we do not have "publish_actions" we need to reauthorize.

In SimpleSessionLogin login looks like this:

private void onClickLogin() {
    Session session = Session.getActiveSession();
    if (!session.isOpened() && !session.isClosed()) {
        session.openForRead(new Session.OpenRequest(this).setCallback(statusCallback));
    } else {
        Session.openActiveSession(this, true, statusCallback);
    }
}

So, I can't figure out how to request permissions during login. It's kind a weird or to say redundant to log in to the service twice in couple of seconds with exactly the same dialog.

It can sound to user that something is wrong or weird.

I want to log to facebook once, with wanted permissions, but using API 3.0 Session calls, not the deprecated one.

Can anyone please explain how?

Upvotes: 14

Views: 20389

Answers (5)

Danuofr
Danuofr

Reputation: 1710

Ok so here is a dialog fragment I made that uses Facebook's 3.0 SDK for Android. It is encapsulated, meaning all of the Facebook functionality is contained in the fragment. This is a dialog fragment so it pops up over your running activity. This fragment lets you login, then enables certain views once you are logged in using the UiHelper class included with Facebook.

public class FFragment extends DialogFragment {

private static final String TAG = "FacebookFragment";
private UiLifecycleHelper uiHelper;
private String mFilePath;
private Button shareButton, cancelButton;
private EditText mMessageText;
private TextView mMessageTitle;
private ProgressBar pBar;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.facebook_login, container, false);
    LoginButton authButton = (LoginButton) view
            .findViewById(R.id.authButton);
    authButton.setFragment(this);
    authButton.setPublishPermissions(Arrays.asList("publish_stream"));

    shareButton = (Button) view.findViewById(R.id.shareButton);
    mMessageText = (EditText) view.findViewById(R.id.facebook_post_text);
    mMessageTitle = (TextView) view.findViewById(R.id.facebook_post_title);
    cancelButton = (Button) view.findViewById(R.id.cancelButton);
    pBar = (ProgressBar) view.findViewById(R.id.facebook_pbar);
    cancelButton.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View arg0) {
            FFragment.this.dismiss();

        }

    });
    shareButton.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View arg0) {
            publishPhoto();

        }

    });
    return view;
}

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

    mFilePath = getArguments().getString("file_path");

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

}

/**
 * After user selects to upload photo
 */
private void publishPhoto() {
    pBar.setVisibility(View.VISIBLE);
    GraphObject graphObject;
    Bitmap bmap = BitmapFactory.decodeFile(mFilePath);

    ByteArrayOutputStream stream = new ByteArrayOutputStream();

    bmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);

    byte[] byteArray = stream.toByteArray();

    Bundle params = new Bundle();

    params.putByteArray("picture", byteArray);
    params.putString("message", mMessageText.getText() + " " + 
            getActivity().getResources().getString("String goes here"));

    Request request = new Request(Session.getActiveSession(), "me/photos",params, 
             HttpMethod.POST);

    request.setCallback(new Request.Callback() {

        @Override
        public void onCompleted(Response response) {
            if (response.getError()==null) {
                Toast.makeText(getActivity(), "Successfully posted photo", Toast.LENGTH_SHORT).show();
                FlurryAgent.logEvent(Globals.EVENT_FACEBOOK);
            } else {
                Toast.makeText(getActivity(), response.getError().getErrorMessage(), Toast.LENGTH_SHORT).show();
            }
            pBar.setVisibility(View.GONE);
            FFragment.this.dismiss();

        }
    });
    request.executeAsync();




}
private void onSessionStateChange(Session session, SessionState state,
        Exception exception) {
    if (state.isOpened()) {
        Log.i(TAG, "Logged in...");
        // Check for reading user_photos permission  
        shareButton.setVisibility(View.VISIBLE);
        mMessageText.setVisibility(View.VISIBLE);
        mMessageTitle.setVisibility(View.VISIBLE);


    } else if (state.isClosed()) {
        Log.i(TAG, "Logged out...");
        shareButton.setVisibility(View.GONE);
        mMessageText.setVisibility(View.GONE);
        mMessageTitle.setVisibility(View.GONE);
    }

}


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

    }
};

@Override
public void onResume() {
    super.onResume();
    uiHelper.onResume();
    // For scenarios where the main activity is launched and user
    // session is not null, the session state change notification
    // may not be triggered. Trigger it if it's open/closed.
    Session session = Session.getActiveSession();
    if (session != null && (session.isOpened() || session.isClosed())) {
        onSessionStateChange(session, session.getState(), null);
    }
}

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

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

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

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

}

The following lines of code are what you would use in your activity to show the dialog.

FFragment mFacebookFragment = new FFragment();
        Bundle args = new Bundle();
        args.putString("file_path", mFilePath);
        mFacebookFragment.setArguments(args);
        mFacebookFragment.show(getSupportFragmentManager(), "tag");

Anyhow if you look on the onCreate we are settings the publish permissions. By default the read permissions are already set when the fragment starts up.

Also make you you have this in the manifest.

<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/app_id"/>

Where @string/app_id is the app id you made when created facbeook application on developers site. Also be sure to download the new sdk facebook project and reference it as a library project. XML File for dialog layout.

 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >



<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:orientation="vertical" >

    <com.facebook.widget.LoginButton
        android:id="@+id/authButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dp"
        android:layout_gravity="center_horizontal|top" />

    <TextView
        android:id="@+id/facebook_post_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:text="Message to post with photo"
        android:textColor="@android:color/white"
        android:textSize="18dp"
        android:textStyle="bold"
        android:visibility="gone" />

    <EditText
        android:id="@+id/facebook_post_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:minLines="3"
        android:visibility="gone" />

    <Button
        android:id="@+id/shareButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:gravity="center"
        android:text="Post"
        android:textStyle="bold"
        android:visibility="gone" />

    <Button
        android:id="@+id/cancelButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="Cancel"
        android:textStyle="bold" />
</LinearLayout>

<ProgressBar 
    android:id="@+id/facebook_pbar"
    android:layout_width="50dp"
    android:layout_height="50dp"
    android:layout_gravity="center"
    android:visibility="gone"
    />

Upvotes: 6

Mani
Mani

Reputation: 777

@Ming Li, When i created a session using

public static final List<String> ALL_PERMISSIONS = Arrays.asList(       
            "read_friendlists",
            "publish_stream",
            "offline_access",
            "email",
            "read_stream",
            "user_location" ); 

session.openForPublish(new Session.OpenRequest(this).setPermissions(ALL_PERMISSIONS).setCallback(statusCallback).setRequestCode(100));

The session obtained, has both the (read and publish) permissions. So i feel users who wants to obtain session with both read and publish can use openForPublish() api. It works...!!

Upvotes: 2

David
David

Reputation: 21

The Facebook 3.0 api is really limiting with not being able to ask for both read and publish at the same time. I did find a workaround though, but you have to modify the library.

Just add this to Session.java:

public final void openForReadAndPublish(OpenRequest openRequest) {
        open(openRequest, null);
    }

This will cause it to skip the validation checks that throw exceptions. Of course you might need to do everything more manual now. You could also just comment out the validatePermissions(openRequest, authType) calls in Session and that should make it so you can pass in any permissions you want.

Upvotes: 2

Jesse Chen
Jesse Chen

Reputation: 4928

When authorizing/logging into the app for the first time you can only request read permissions. I was trying out this new SDK earlier as well and was slightly confused as well.

Facebook wants the user to be more confident in your app's publishing abilities by making it so you have to reauthorize for publishing permissions the first time you want to publish an OG action. If you look at the way Foursquare or Instagram publishes OG, they have a Facebook checkbox or button to indicate that you want to share the action on FB. You can implement something similar to that or what I ended up doing, is to display a button after the user has authorized the app that asks them to click to enable publishing actions to Facebook.

Upvotes: 4

Ming Li
Ming Li

Reputation: 15662

The Session.OpenRequest has a method where you can set permissions. However, with the 3.0 SDK, Facebook is now requesting that developers request "read" and "publish" permissions separately. So if your app needs to both read user info and publish on their behalf, then you'll need to call reauthorize.

Upvotes: 8

Related Questions