Requesting new permissions fail handling - android

Login and asking permission works just fine. But there is one problem: I need to ask publish permission when user wants to share some date from my app. Here is my code:
ParseFacebookUtils.getSession().requestNewPublishPermissions(new NewPermissionsRequest((Activity) context,
Arrays.asList(Permissions.Extended.PUBLISH_ACTIONS, Permissions.Extended.PUBLISH_STREAM))
.setCallback(new StatusCallback() {
#Override
public void call(Session session, SessionState state, Exception exception) {
if (!arePublishPermissionsEnabled(session)) {
inflow.setChecked(false);
facebook.setChecked(false);
twitter.setChecked(false);
}
}
}));
The problem is in handling situation when user canceled request or there is a loss of network connection. In this case I need to do some changes in my UI, but method call is calling only when session state is changed (e.g. granted new permissions) and I can't properly changed my UI. Is anyone faced such problem?

private void requestPublishPermissions(Session session) {
List<String> PERMISSIONS = Arrays.asList("publish_actions", "publish_stream");
if (session != null) {
pendingAnnounce = true;
Session.NewPermissionsRequest newPermissionsRequest = new Session.NewPermissionsRequest(this, PERMISSIONS);
newPermissionsRequest.setRequestCode(REAUTH_ACTIVITY_CODE);
Session mSession = Session.openActiveSessionFromCache(this);
mSession.addCallback(callback);
mSession.requestNewPublishPermissions(newPermissionsRequest);
}
}

Related

Facebook asking write permissions

I've encountered a problem. During login I ask read permissions, that seems to work fine, but whenever I want to share something I use this method to check for required permissions:
public interface OnWritePermissionListener {
public void result(boolean success);
}
public void askWritePermissions(final OnWritePermissionListener listener) {
if (!getSession().getPermissions().containsAll(writePermissions)) {
L.d("Requesting write permissions.");
Session.NewPermissionsRequest newPermissionsRequest = new Session.NewPermissionsRequest(activity, writePermissions);
newPermissionsRequest.setCallback(new StatusCallback() {
#Override
public void call(Session session, SessionState state, Exception exception) {
L.d("Status callback for askWritePermissions. State: %s. Exception: %s.", state.name(), exception == null ? "none" : exception.toString());
if (session.getPermissions().containsAll(writePermissions)) {
listener.result(true);
} else {
listener.result(false);
}
}
});
getSession().requestNewPublishPermissions(newPermissionsRequest);
} else {
L.d("Write permissions already granted.");
listener.result(true);
}
return;
}
writePermissions contains string entry: "publish_actions"
The problem is that when I call this method the FB window appears only for a half second and then dissapears calling listener.result(false). Log shows this:
Status callback for askWritePermissions. State: OPENED_TOKEN_UPDATED. Exception: none.
Any ideas what I might be doing wrong?

Ask for additional facebook permission

I'm having trouble while trying to retrieve an additional permission "publish_action".
I assume that user has already logged in via facebook thus basic permissions are granted.
Then I have this code (from my fragment):
List<String> permissionsRequested = Arrays.asList("publish_actions");
List<String> permissionsActual = session.getPermissions();
if (!isSubsetOf(permissionsRequested, permissionsActual)) {
pendingPublishReauthorization = true;
Session.NewPermissionsRequest newPermissionsRequest = new Session
.NewPermissionsRequest(this, permissionsRequested);
session.requestNewPublishPermissions(newPermissionsRequest);
return;
}
Seeing from debug, after user grants permission, control goes to onActivityResult, where, according to facebook docs, I have
super.onActivityResult(requestCode, resultCode, data);
facebookUiHelper.onActivityResult(requestCode, resultCode, data);
uiHelper is also properly (acording to the docs) used in all those onResume&onDestroy methods.
In onCreate I have
super.onCreate(savedInstanceState);
facebookUiHelper = new UiLifecycleHelper(getActivity(), fbSessionCallback);
facebookUiHelper.onCreate(savedInstanceState);
where fbSessionCallback has overridden call() method, that calls my onFbSessionRestore():
if (pendingPublishReauthorization &&
state.equals(SessionState.OPENED_TOKEN_UPDATED)) {
pendingPublishReauthorization = false;
// do things with my new session, updated with granted permission. e.g. post to fb.
}
Trouble is that
onActivityResult executes, but after that no callback ever called, so that overridden call() won't go, and onFbSessionCallback either.
If I try to post again (start things from scratch) after that - it gets session without granted permission again, tries to request it and then goes facebook exception about pending newPublishRequest permission blah-blah
Can someone help to configure workflow from onActivityResult and later?
I read facebook docs and I tend to blame they are written badly. Maybe it's just me too stupid... :(((
This is how I have set it up:
Session session = Session.getActiveSession();
if (session != null) {
List<String> permissions = session.getPermissions();
if (!permissions.contains("publish_actions")) {
Session.NewPermissionsRequest newPermissionsRequest = new Session.NewPermissionsRequest(this, "publish_actions");
session.addCallback(callbacktwo);
session.requestNewPublishPermissions(newPermissionsRequest);
return;
}
}
This is in my onActivityResult but it doesn't need to be. I have used it in my onCreate before. I added a callback to the request which I can then use to do my next step.
Here is my callback:
private Session.StatusCallback callbacktwo = new Session.StatusCallback() {
#Override
public void call(Session session, SessionState state, Exception exception) {
Intent in = new Intent(getActivity(), ClassHere.class);
startActivity(in);
}
};
Remember that the callback will respond twice, once when you start a permission request, and after it is completed. So you have to work around that/work that into your code.

Get Facebook user email using latest Facebook SDK

I'm developing an Android application, and I'm using this code to get some data from Facebook:
public void onFBLoginClick(View view)
{
// start Facebook Login
Session.openActiveSession(this, true, new Session.StatusCallback()
{
// callback when session changes state
#Override
public void call(final Session session, SessionState state, Exception exception)
{
if (session.isOpened())
{
// make request to the /me API
Request.executeMeRequestAsync(session, new Request.GraphUserCallback()
{
// callback after Graph API response with user object
#Override
public void onCompleted(GraphUser user, Response response)
{
if (user != null)
{
txtUserName.setText(session.getAccessToken());
saveUserData(user.getId(), user.getName(), user.getBirthday(), user.asMap().get("email").toString());
saveAccessToken(session.getAccessToken());
getFacebookUserProfilePicture(session.getAccessToken());
}
}
});
}
}
});
}
But, I can't get the email. Always is null.
I set up email permissions on User & Friend Permissions, on developers.facebook.com, but it doesn't work.
What am I doing wrong?
Use this code to open your session and you are ready to go!
String[] PERMISSION_ARRAY_READ = {"email","user_birthday"};
List<String> PERMISSION_LIST=Arrays.asList(PERMISSION_ARRAY_READ);
session.openForRead(new Session.OpenRequest(getParent()).setPermissions(PERMISSION_LIST).setCallback(statusCallback));
let me know if uyou have any problem regarding this.

User is asked for login credentials during reauthorization

I am trying to implement the new Facebook SDK 3.0 into my Android app and I have run into a problem. The problem I am having is that the user is asked to log in again to give publish ("post_to_wall") permissions, even though the user is already logged in, with read permissions. This only happens if the user doesn't have the FB application installed. If he has the FB application installed, then he is only asked to grant the permissions.
This is how I implemented the login:
public void login(Activity activity) {
Session session = Session.getActiveSession();
if (session == null || !session.isOpened()) {
openActiveSession(activity, true, sessionStatusCallback);
}
}
private Session openActiveSession(final Activity activity, final boolean allowLoginUI, final StatusCallback callback) {
return openActiveSession(activity, allowLoginUI, new OpenRequest(activity).setCallback(callback));
}
private Session openActiveSession(final Context context, final boolean allowLoginUI, final OpenRequest openRequest) {
Session session = new Builder(context).setApplicationId(FACEBOOK_APPLICATION_ID).build();
if (SessionState.CREATED_TOKEN_LOADED.equals(session.getState()) || allowLoginUI) {
Session.setActiveSession(session);
session.openForRead(openRequest);
return session;
}
return null;
}
This is the callback's call method:
public void call(final Session session, final SessionState state, final Exception exception) {
if (session.isOpened()) {
if (state.equals(SessionState.OPENED_TOKEN_UPDATED)) {
// code if new permissions have been granted
} else {
// code for login
}
} else if (session.isClosed()) {
// code for user canceled login
} else if (exception != null) {
// code if there were errors during login
}
}
}
This is the code I added to onActivityResult method of the activity that calls the login:
Session.getActiveSession().onActivityResult(activity, requestCode, resultCode, data);
And this is how I ask for new permissions:
Session session = Session.getActiveSession();
if (session != null && session.isOpened()) {
if (DONT_HAVE_PERMISSIONS) {
Session.NewPermissionsRequest newPermissionsRequest = new Session.NewPermissionsRequest(activity,
FACEBOOK_PERMISSIONS).setRequestCode(FACEBOOK_AUTHORIZE_ACTIVITY_CODE);
session.requestNewPublishPermissions(newPermissionsRequest);
}
}
I've tried to find out more about this problem, and I only found out some hints that this is intended, but I haven't found anything concrete.
Is this the default behavior? If so, is there a way around it? Or, perhaps I did something wrong?
Thanks for the help.
Update your SDK version; this issue is resolved in Facebook Android SDK v3.0.1.
Looking at facebooks source code I think it should be possible to start trying to get the permissions directly as both login, and permissions classes derive from the same AuthorizationRequest class, and the AuthorizationRequest class does all the work, like really all the work. The Session.NewPermissionsRequest class just makes some private methods, public in the AuthorizationRequest class and that's it! They might as well give us access to AuthorizationRequest directly. The new facebook API doesn't seem to have any form of "OnFailed/OnSuccess" callbacks, so I end up having a state machine to remember the goal of firing up facebook (login, permissions, get friends list ...), and which step I'm on. If they have done some form of onFailed/onSuccess callbacks it would be simple to make a chain rather than keeping track of a state machine.
I haven't tried what I said. If I do, I'll update the answer. If you try and it works to just fire up Session.NewPermissionsRequest directly without logging in let me know!
Update
I got it working with only asking for credentials once as I explained above.
goto src/com/facebook/Sessions.java
On line 862 you will find
private static Session openActiveSession(Context context, boolean allowLoginUI, OpenRequest openRequest)
make it be a public function and save.
Now instead of creating the Session.NewPermissionsRequest object. Make Session.OpenRequest
permisions = new ArrayList<String>();
permisions.add("user_photos");
permisions.add("friends_photos");
Session.NewPermissionsRequest request = new Session.NewPermissionsRequest(
activity, permisions);
request.setCallback(helper);
if (Session.getActiveSession() != null)
Session.getActiveSession().requestNewReadPermissions(request);
else {
Session.OpenRequest orequest = new Session.OpenRequest(activity);
orequest.setPermissions(permisions);
orequest.setCallback(helper);
// its now public so you can call it
Session.openActiveSession(act, true, request);
}
Now make sure you do set a callback, for one important reason
#Override
public void call(Session session, SessionState state, Exception exception) {
if (state.isClosed()) {
// we are doing unofficial stuff so we loose guarantees.
// Set the active session to null if we logout or user cancels
// logging in. If you don't do this, the second time it will result
// in a crash.
Session.setActiveSession(null);
}
}
Now it will ask for all permissions directly and login in one go.

StatusCallback not called after requestNewReadPermissions then requestNewPublishPermissions

I am developing an Android App that integrates with Facebook. I would like to:
Let the user login with Facebook
Get the user's email address on Facebook (could be a proxied email address, which is fine)
Post to the user's wall/timeline on his/her behalf
Technically, that would be to:
Authenticate the user
Request the email permission
Request the publish_stream permission
1. Authenticate the user
I called Session.openActiveSession() with a Session.StatusCallback (I already checked that there is no active opened session beforehand):
final Session.StatusCallback sessionStatusCallback = new Session.StatusCallback() {
public void call(final Session session, SessionState state, Exception exception) {
// If there is an exception...
if(exception != null)
{
// Handle fail case here.
return;
}
// If session is just opened...
if(state == SessionState.OPENED)
{
// Handle success case here.
return;
}
};
};
// Start Facebook Login.
Session.openActiveSession(activity, true, sessionStatusCallback);
My callback is called after successful login. So far so good.
2. Request the email permission
This is my status callback:
new Session.StatusCallback() {
public void call(final Session session, SessionState state, Exception exception) {
// If there is an exception...
if(exception != null)
{
// Handle fail case here.
return;
}
// If token is just updated...
if(state == SessionState.OPENED_TOKEN_UPDATED)
{
// Handle success case here.
return;
}
};
};
I request the permission with Session.requestNewReadPermissions():
final Session session = Session.getActiveSession();
final static String[] PERMISSION_ARRAY_READ = {"email"};
final List<String> permissionList = Arrays.asList(PERMISSION_ARRAY_READ);
// If all required permissions are available...
if(session.getPermissions().containsAll(permissionList))
{
// Handle success case here.
return;
}
// Request permissions.
session.requestNewReadPermissions(new Session.NewPermissionsRequest(activity, permissionList));
My callback is called after permission is granted. So far so good.
3. Request the publish_stream permission
This is my status callback:
new Session.StatusCallback() {
public void call(final Session session, SessionState state, Exception exception) {
// If there is an exception...
if(exception != null)
{
// Handle fail case here.
return;
}
// If token is just updated...
if(state == SessionState.OPENED_TOKEN_UPDATED)
{
// Handle success case here.
return;
}
};
};
I request the permission with Session.requestNewPublishPermissions():
final Session session = Session.getActiveSession();
final static String[] PERMISSION_ARRAY_PUBLISH = {"publish_stream"};
final List<String> permissionList = Arrays.asList(PERMISSION_ARRAY_PUBLISH);
// If all required permissions are available...
if(session.getPermissions().containsAll(permissionList))
{
// Handle success case here.
return;
}
// Request permissions.
session.requestNewPublishPermissions(new Session.NewPermissionsRequest(activity, permissionList));
This time, my callback is not called after permission is granted.
Investigation
Upon further investigation, I found that my callback is triggered by com.facebook.Session#postStateChange(SessionState, SessionState, Exception):
void postStateChange(final SessionState oldState, final SessionState newState, final Exception exception) {
if (oldState == newState && exception == null) {
return;
}
/* ... */
}
Since oldState and newState are equal (both being SessionState.OPENED_TOKEN_UPDATED, my callback is not called.
Question
How can I receive any notification after permission is granted for the 2nd time? Am I supposed to close() the session and re-open it from cache?
Additional info
My Facebook Android SDK 3.0 is download from here, which is stated in Facebook's Getting Started with the Facebook SDK for Android.
This is a bug.
[edit: As Guy points out in comments, this was fixed in 3.0.1, so this workaround is no longer necessary]
The workaround you mention is basically correct, though you do not need to call close. If you are using the single active session, before calling requestNewPublishPermissions() just call:
Session.openActiveSessionFromCache(myContext);
If you are using multiple sessions, you need to initialize a new Session with the TokenCachingStrategy, verify it is in the CREATED_TOKEN_LOADED state, and call openForRead(null);
After doing one of these, requestNewPublishPermissions() should call your notification once it completes.
Working code based on rightparen's answer
Before requesting permission for the 2nd time (i.e. before Session.requestNewPublishPermissions()), do this:
// Re-initialize Facebook session.
session.removeCallback(sessionStatusCallback); // Remove callback from old session.
session = Session.openActiveSessionFromCache(context); // Create new session by re-opening from cache.
session.addCallback(sessionStatusCallback); // Add callback to new session.
Code is still based on Facebook Android SDK 3.0, as in the question.
Another thing I ran into was that my requestCode for the NewPermissionRequest was not being set to the same requestCode that I used to open my Session for Read with, thereby my Session.StatusCallback was never being invoked when the new permissions have been granted.
For instance, in my onActivityResult I have a check for the requestCode and delegate the call accordingly because I have other stuff coming in to this method.
public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
if (requestCode == FACEBOOK_AUTH_RESULT_CODE) {
Session session = Session.getActiveSession();
if(session != null) {
session.onActivityResult(activity, requestCode, resultCode, data);
}
}
}
I then opened my Session with the following code :
Session.getActiveSession().openForRead(
new Session.OpenRequest(activity).
setLoginBehavior(SessionLoginBehavior.SSO_WITH_FALLBACK).
setRequestCode(FACEBOOK_AUTH_RESULT_CODE).
setPermissions(MY_READ_PERMISSIONS));
I then forgot to use the same requestCode when constructing my NewPermissionRequest.
This is what the correct NewPermissionRequest needs to look like :
Session.getActiveSession().requestNewPublishPermissions(
new NewPermissionsRequest(activity, MY_PUBLISH_PERMISSIONS)
.setRequestCode(FACEBOOK_AUTH_RESULT_CODE));

Categories

Resources