I'm trying to give users an option to set/revoke publishing permission via checkbox (Facebook SDK for Android). Code is provided below. Everything works fine except that after revoking the code responsible for checking publishing permissions fails miserably.
I understand that Session has no way of knowing if user has revoked any permissions after loggin in. What is the correct way to handle this kind of situation? Do I have to query available permissions manually, or is there a way to seamlessly recreate session with basic permissions?
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
publishCheckbox = (CheckBox) view.findViewById(R.id.publishCheckbox);
publishCheckbox.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
CheckBox chb = (CheckBox) v;
if (chb.isChecked() && checkForPublishPermission() == false){
requestPublishPermissions();
}
else{
removePublishPermissions();
}
}
});
...
}
private void requestPublishPermissions() {
Session session = Session.getActiveSession();
if ( session!= null && session.isOpened()){
Session.NewPermissionsRequest newPermissionsRequest = new Session.NewPermissionsRequest(this, PERMISSIONS).setRequestCode(REAUTH_ACTIVITY_CODE);
newPermissionsRequest.setCallback(callback);
session.requestNewPublishPermissions(newPermissionsRequest);
}
}
private void removePublishPermissions() {
Request r = new Request(Session.getActiveSession(), PUBLISH_ACTIONS_PERMISSION_PATH, null, HttpMethod.DELETE);
r.setCallback(new Request.Callback() {
#Override
public void onCompleted(Response response) {
publishCheckbox.setEnabled(true);
}
});
r.executeAsync();
publishCheckbox.setEnabled(false);
}
private boolean checkForPublishPermission(){
boolean result = false;
Session session = Session.getActiveSession();
if (session == null || !session.isOpened()) {
result = false;
}
else{
List<String> permissions = session.getPermissions();
if (permissions.containsAll(PERMISSIONS)) {
result = true;
}
}
return(result);
}
private void onSessionStateChange(Session session, SessionState state, Exception exception) {
if (state.isOpened()) {
...
publishCheckbox.setChecked(checkForPublishPermission());
...
} else if (state.isClosed()) {
...
}
}
Well I ended up requesting user permissions each time I needed such a check, something along these lines:
private void checkForPublishPermission(){
mPublishCheckbox.setEnabled(false);
Request r = new Request(Session.getActiveSession(), PUBLISH_ACTIONS_PERMISSION_PATH, null, HttpMethod.GET);
r.setCallback(new Request.Callback() {
#Override
public void onCompleted(Response response) {
if (response != null) {
GraphObject o = response.getGraphObject();
if ( o != null){
JSONArray data = o.getInnerJSONObject().optJSONArray("data");
mCanPublish = (data.optJSONObject(0).has("publish_actions"))?true:false;
mPublishCheckbox.setChecked(mCanPublish);
}
}
mPublishCheckbox.setEnabled(true);
}
});
r.executeAsync();
}
Related
I am using Facebook SDK for my android app.It's log in successfully but after that when i want to access graph api it shows Should not pass a read permission (email) to a request for publish or manage authorization and crashes my apk with null pointer exception.
when i use SessionLoginBehavior.SUPPRESS_SSO it works fine but while using SessionLoginBehavior.SSO_WITH_FALLBACK it show this error
Below is my FacebookService class.
public class FacebookService {
private Context context;
private Session session;
private Session.StatusCallback statusCallback;
private List<String> permissions = Arrays.asList("email", "user_checkins", "user_birthday", "user_hometown",
"user_location");
private FacebookRequestListener facebookRequestListener;
private String profile_url;
public interface FacebookRequestListener {
void signedInFacebookUser(RamblerUser user);
void errorOccuredOnFacebook();
}
public FacebookService(Context context) {
this.context = context;
statusCallback = new SessionStatusCallback();
}
public void login() {
if (session == null) {
session = new Session(context);
Session.setActiveSession(session);
}
setupRequest();
}
public void logOut() {
session = Session.getActiveSession();
if (!session.isClosed()) {
session.closeAndClearTokenInformation();
}
}
public Boolean isSessionAvailable() {
if (session == null)
return false;
else
return session.isOpened();
}
private void setupRequest() {
OpenRequest request = new Session.OpenRequest(((Activity) context));
request.setLoginBehavior(SessionLoginBehavior.SSO_WITH_FALLBACK);
request.setCallback(statusCallback);
request.setPermissions(permissions);
session.openForPublish(request);
}
private class SessionStatusCallback implements Session.StatusCallback {
#Override
public void call(Session session, SessionState state, Exception exception) {
if (session.isOpened()) {
callProfilePictureApi();
}
}
}
public void addCallback() {
if (session != null) {
if (statusCallback != null)
Session.getActiveSession().addCallback(statusCallback);
}
}
public void removeCallback() {
if (session != null) {
if (statusCallback != null)
Session.getActiveSession().removeCallback(statusCallback);
}
}
public void activityResult(int requestCode, int resultCode, Intent data) {
Session.getActiveSession().onActivityResult(((Activity) context), requestCode, resultCode, data);
}
public void setFacebookRequestListener(FacebookRequestListener facebookRequestListener) {
this.facebookRequestListener = facebookRequestListener;
}
private void callProfilePictureApi() {
Bundle params = new Bundle();
params.putBoolean("redirect", false);
params.putString("height", "200");
params.putString("type", "normal");
params.putString("width", "200");
/* make the API call */
new Request(session, "/me/picture", params, HttpMethod.GET, new Request.Callback() {
public void onCompleted(Response response) {
/* handle the result */
GraphObject go = response.getGraphObject();
// go.getProperty("url");
JSONObject obj = go.getInnerJSONObject();
try {
profile_url = obj.getJSONObject("data").get("url").toString();
callProfileApi();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
facebookRequestListener.errorOccuredOnFacebook();
}
}
}).executeAsync();
}
private void callProfileApi() {
Request.newMeRequest(session, new Request.GraphUserCallback() {
#Override
public void onCompleted(GraphUser user, Response response) {
// TODO Auto-generated method stub
if (user != null) {
String email = user.asMap().get("email").toString();
// Log.i("profile url", ""+
RamblerUser rambleUser = new RamblerUser();
rambleUser.socialId = user.getId();
rambleUser.address = user.getLocation() != null ? user.getLocation().getName() : "NA";
rambleUser.email = user.asMap().get("email").toString();
rambleUser.socialType = com.rambler.Rambler.LoginType.GPlus;
rambleUser.gender = "NA";
rambleUser.socilaProfileImageUrl = "NA";
rambleUser.socilaProfileImageUrl = profile_url;
rambleUser.name = user.getName();
rambleUser.screenName = user.getUsername();
Log.i("email address", email);
facebookRequestListener.signedInFacebookUser(rambleUser);
} else {
facebookRequestListener.errorOccuredOnFacebook();
}
}
}).executeAsync();
}
}
Use ReadPermissions instead of PublishPermissions. You are trying to request read permissions with a function that is being used for publish permissions.
I'm unable to add permission for birthday, please help me out...
thanks in advance.
sample source code is :
Session.openActiveSession(this, true, new Session.StatusCallback() {
// callback when session changes state
#SuppressWarnings("deprecation")
#Override
public void call(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) {
}
}
});
}
}
});
Try this,
.setPermissions(Arrays.asList("user_birthday","email"))
private static final List PERMISSIONS = Arrays.asList(""user_birthday""); //declaration
onClickPostStatusUpdate();// on button click call this function
private void onClickPostStatusUpdate() {
performPublish(PendingAction.POST_STATUS_UPDATE);
}
private void performPublish(PendingAction action) {
Session session = Session.getActiveSession();
if (session != null) {
pendingAction = action;
if (hasPublishPermission()) {
// We can do the action right away.
handlePendingAction();
} else {
// We need to get new permissions, then complete the action when we get called back.
session.requestNewPublishPermissions(new Session.NewPermissionsRequest(this, PERMISSIONS));
}
}
}
user.getBirthday();
I remeber using that and storing it as a string.
i am getting a null when i try to fetch my friend's birthday . this is where i set the permissions
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View view = inflater.inflate(R.layout.activity_main, container, false);
LoginButton authButton = (LoginButton) view
.findViewById(R.id.authButton);
authButton.setFragment(this);
authButton.setReadPermissions(Arrays.asList("user_likes",
"friends_birthday", "friends_about_me"));
return view;
// return super.onCreateView(inflater, container, savedInstanceState);
}
and this is how i am trying to fetch birthdays
private void onSessionStateChange(Session session, SessionState state,
Exception exception) {
if (state.isOpened()) {
Log.i(TAG, "Logged in...");
Request.executeMyFriendsRequestAsync(session,
new Request.GraphUserListCallback() {
#Override
public void onCompleted(List<GraphUser> users,
Response response) {
// TODO Auto-generated method stub
// Log.i("Response JSON", response.toString());
names = new String[users.size()];
id = new String[users.size()];
for (int i = 0; i < users.size(); i++) {
names[i] = users.get(i).getBirthday();
//id[i] = users.get(i).ge();
Log.i("Birthday chakk te bai ", "Birthday"
+ names[i]);
}
}
});
} else if (state.isClosed()) {
Log.i(TAG, "Logged out...");
}
}
Please see why i am geeting null . Every thing is fine with keyhash as i tested it for friends name .
App is only in the sandbox mode.
Try this-
Your callback, where you'll get friends and birthday info(if authenticated):
Session.StatusCallback statusCallback = new Session.StatusCallback()
{
// callback when session changes state
#Override
public void call(Session session, SessionState state, Exception exception)
{
if (session.isOpened())
{
getFriendDetails();
}
}
};
Then, open the session and set the permissions:
Session session = new Session(this);
session.openForRead(new Session.OpenRequest(this)
.setCallback(statusCallback)
.setPermissions(Arrays.asList("friends_birthday")));
As a last step, get the friends birthday and other details:
private void getFriendDetails()
{
Request myFriendsRequest = Request.newMyFriendsRequest(Session.getActiveSession(),
new Request.GraphUserListCallback()
{
#Override
public void onCompleted(List<GraphUser> users, Response response)
{
if (response.getError() == null)
{
// Print response
}
}
});
Bundle requestParams = myFriendsRequest.getParameters();
requestParams.putString("fields", "name,birthday");
myFriendsRequest.setParameters(requestParams);
myFriendsRequest.executeAsync();
}
I am working on facebook integration in an android app. I did a lot of search about error handling of facebook inn android but nothing foung. Can anyone tell me how handle these situation in android :
1.The user changes her password which invalidates the access token.
2.The user de-authorizes your app.
3.The user logs out of Facebook.
My code of facebook integration is here :
private UiLifecycleHelper uiHelper;
private Session.StatusCallback callback = new Session.StatusCallback() {
#Override
public void call(Session session, SessionState state, Exception exception) {
onSessionStateChange(session, state, exception);
}
};
private void onSessionStateChange(Session session, SessionState state, Exception exception) {
if ( exception instanceof FacebookOperationCanceledException ||
exception instanceof FacebookAuthorizationException)
{
new AlertDialog.Builder(MainWindow.this)
.setTitle("cancel")
.setMessage("your permission has expired.")
.setPositiveButton("ok", null)
.show();
}
}
private void onClickFacebookRequest()
{
if (session.isOpened())
{
sendRequests();
} else {
StatusCallback callback = new StatusCallback() {
public void call(Session session, SessionState state, Exception exception) {
if (exception != null) {
new AlertDialog.Builder(MainWindow.this)
.setTitle(R.string.login_failed_dialog_title)
.setMessage(exception.getMessage())
.setPositiveButton(R.string.ok_button, null)
.show();
session = createSession();
}
}
};
pendingRequest = true;
session.openForRead(new Session.OpenRequest(this).setCallback(callback));
}
}
private static final List<String> PERMISSIONS = Arrays.asList("publish_actions");
private static final String PENDING_PUBLISH_KEY = "pendingPublishReauthorization";
private void sendRequests()
{
List<String> permissions = quytechApps.getSession().getPermissions();
if (!isSubsetOf(PERMISSIONS, permissions)) {
pendingRequest = true;
Session.NewPermissionsRequest newPermissionsRequest = new Session
.NewPermissionsRequest(this, PERMISSIONS);
session.requestNewPublishPermissions(newPermissionsRequest);
return;
}
showValidationDialog("Please Wait.posting Data on Facebook");
Bitmap image = BitmapFactory.decodeResource(this.getResources(), R.drawable.splash_screen_final4);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
Bundle postParams=new Bundle();
postParams.putByteArray("photo",byteArray);
postParams.putString("message", "Hi Friends I am using Twinqli Chat App.");
Request request = new Request(Session.getActiveSession(), "me/photos", postParams, HttpMethod.POST, new Request.Callback()
{
#Override
public void onCompleted(Response response) {
// TODO Auto-generated method stub
// showPublishResult(getString(R.string.photo_post), response.getGraphObject(), response.getError());
if(response.getError() == null)
{
Log.d("GraphApiSample.java Sucesses","sucess");
dismissValidatingDialog();
}
else
{
dismissValidatingDialog();
session.closeAndClearTokenInformation();
//quytechApps.getSession().
//quytechApps.setSession(null);
// Log.d("GraphApiSample.java",""+response.getError().getErrorMessage());
}
}
});
request.executeAsync();
}
private boolean isSubsetOf(Collection<String> subset, Collection<String> superset) {
for (String string : subset) {
if (!superset.contains(string)) {
return false;
}
}
return true;
}
static final String applicationId = "390611174384274";
boolean pendingRequest;
static final String PENDING_REQUEST_BUNDLE_KEY = "com.facebook.samples.graphapi:PendingRequest";
private Session createSession()
{
Session activeSession = Session.getActiveSession();
if (activeSession == null || activeSession.getState().isClosed())
{
activeSession = new Session.Builder(this).setApplicationId(applicationId).build();
Session.setActiveSession(activeSession);
}
return activeSession;
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (qsession.onActivityResult(this, requestCode, resultCode, data) &&
pendingRequest &&
session.getState().isOpened()) {
sendRequests();
}
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
pendingRequest = savedInstanceState.getBoolean(PENDING_REQUEST_BUNDLE_KEY, pendingRequest);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(PENDING_REQUEST_BUNDLE_KEY, pendingRequest);
}
can anyone help me . Thanks in advance.
The handleError() method noted by Ming Li is relevant to request errors. It does not handle login errors. I have not seen any examples in the Facebook docs, nor samples, as to how to handle login errors, beyond differentiating between a cancellation and an error. My suggestion is to generate erroneous conditions prior to login attempts (e.g. change the password, deauthorize the app, etc), then in the login callback look at the different values you get for error.getMessage(), and build your own mechanisms accordingly (e.g. if the word "session" appears in the message, tell the user to login to the Facebook app). Also note that getLocalizedMessage() seems not to work (as of SDK 3.5.2). You can differentiate between cancels and errors by if (exception instanceof FacebookOperationCanceledException) and if (exception instanceof FacebookAuthorizationException), but that's pretty much it.
This question is related to face book error handling and is very complex to handle .
However, when i was using the face book API, i got a list of error codes that might be returned and as a result i was able to gracefully solve this scenario . I guess what you are asking for , is graceful error handling.
First of all if it is so, a search in google reveals this url.
Now off to the fun part :
Invalidation of access token : Here the error description is : Invalid OAuth 2.0 Access Token and the error number returned is : 190
User De authorirization : This is a permission issue, so error desc is : Permissions error and error no is : 200
User logs out : When user logs out, it will lead to user data error . The error desc is : User data failure and error no is : 310.
But, there are other scenarios as well, which you need to consider. For this you can get a list of all these error codes here in this LINK .
The error handling document is here - https://developers.facebook.com/docs/reference/api/errors/
You should also look at the Scrumptious sample app, specifically the handleError() method in SelectionFragment.java, it breaks down the different cases you should handle.
I'm trying to get the user email and birthday (using a Me request). My app has email and user_birthday permissions and the fb account i'm using has an email and a birthday set.
When I try using the 'Graph API Explorer' (https://developers.facebook.com/tools/explorer) using the user access_token with 'fields=id,email,birthday' all I get is the id.
Can anybody advice me on this please.
Here is my code:
Session.openActiveSession(this, true, new Session.StatusCallback() {
// callback when session changes state
#Override
public void call(Session session, SessionState state, Exception exception) {
if (session.isOpened()) {
// make request to the /me API
Request request = Request.newMeRequest(session, new Request.GraphUserCallback() {
// callback after Graph API response with user object
#Override
public void onCompleted(GraphUser user, Response response) {
if (user != null) {
// here I check the infos I got.
Log.d("some tag", user.getInnerJSONObject().toString()); // it shows only the id, no email or birthday.
if (Session.getActiveSession() != null) {
Log.i(TAG, "Log out from FB");
Session.getActiveSession().closeAndClearTokenInformation();
}
}
}
});
// set params.
request.getParameters().putString("fields", "id,email,birthday");
// execute request.
request.executeAsync();
Log.d(TAG, request.toString());
}
if (exception != null) {
exception.printStackTrace();
}
}
});
Many thanks.
I finally changed the approach using the OpenRequest instead of getMeRequest:
Here is my code:
public void onClick(View v) {
Logger.d(TAG, "Start FB session");
// check if a session exists.
Session currentSession = Session.getActiveSession();
if (currentSession == null || currentSession.getState().isClosed()) {
// create a new session.
Session session = new Session.Builder(getApplicationContext()).build();
// set it a the active session.
Session.setActiveSession(session);
// keep a variable link to session.
currentSession = session;
}
// if a session is already open then issue a request using the available
// session. Otherwise ask for user credentials.
if (currentSession.isOpened()) {
// The user is logged in.
Logger.e(TAG, "User is logged in.");
Session.getActiveSession().closeAndClearTokenInformation();
Logger.i(TAG, "Session closed an token information cleared.");
// get user data here with no extra call.
Session.openActiveSession(this, true, new Session.StatusCallback() {
#Override
public void call(final Session session, SessionState state, Exception exception) {
if (session.isOpened()) {
Request.executeMeRequestAsync(session, new Request.GraphUserCallback() {
#Override
public void onCompleted(GraphUser user, Response response) {
if (user != null) {
Logger.i(TAG, "User:" + user.getInnerJSONObject());
}
}
});
}
}
});
} else {
// Ask for username and password
OpenRequest op = new Session.OpenRequest((Activity) this);
// don't use SSO.
op.setLoginBehavior(SessionLoginBehavior.SUPPRESS_SSO);
// no callback needed.
op.setCallback(null);
// set permissions.
List<String> permissions = new ArrayList<String>();
permissions.add("email");
permissions.add("user_birthday");
op.setPermissions(permissions);
// open session for read.
currentSession.openForRead(op);
Logger.d(TAG, "Session open for read request issued.");
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
Logger.d(TAG, "Request code is: " + requestCode);
Logger.d(TAG, "Result code is: " + resultCode);
super.onActivityResult(requestCode, resultCode, data);
if (Session.getActiveSession() != null)
Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data);
Session currentSession = Session.getActiveSession();
if (currentSession == null || currentSession.getState().isClosed()) {
Session session = new Session.Builder(getApplicationContext()).build();
Session.setActiveSession(session);
currentSession = session;
}
if (currentSession.isOpened()) {
Session.openActiveSession(this, true, new Session.StatusCallback() {
#Override
public void call(final Session session, SessionState state, Exception exception) {
if (session.isOpened()) {
Request.executeMeRequestAsync(session, new Request.GraphUserCallback() {
#Override
public void onCompleted(GraphUser user, Response response) {
if (user != null) {
Logger.i(TAG, "User:" + user.getInnerJSONObject());
}
}
});
}
}
});
}
}
I hope this helps.
When you are using Request.GraphUserCallback(), its best to use it in MAIN UI THREAD
Session s = Session.getActiveSession();
if(s!=null)
{
Request.executeMeRequestAsync(s,new Request.GraphUserCallback()
{
#Override
public void onCompleted(GraphUser user, Response response)
{
if(user!=null)
{
try {
String fbid=null;
String birthday=null;
fbid=user.getId();
birthday=user.getBirthday();
} catch (JSONException e1) {
e1.printStackTrace();
}
}
}
});
}
you can try this also before the Request.executeMeRequestAsync(...){...}
List<String> permissions = session.getPermissions();
List<String> permissionsBirthday = new ArrayList<String>();
permissionsBirthday.add("user_birthday");
if (!isSubsetOf(permissionsBirthday, permissions)) {
pendingPublishReauthorization = true;
Session.NewPermissionsRequest newPermissionsRequest = new Session.NewPermissionsRequest(this, permissionsBirthday);
if (setPermissions(session, newPermissionsRequest))
return;
}
the method isSubsetOf();
private boolean isSubsetOf(Collection<String> subset, Collection<String> superset) {
for (String string : subset) {
if (!superset.contains(string)) {
return false;
}
}
return true;
}
hope this helps.
This code worked for me hope you find it useful. This retrieves the user email in 3 different ways and also logs it
try{
// new Read().execute("Facebook");
Session.openActiveSession(this, true, new Session.StatusCallback() {
// callback when session changes state
#Override
public void call(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) {
// TextView welcome = (TextView) findViewById(R.id.welcome);
// welcome.setText("Hello " + user.getName() + "!");
Log.d("useremai", (String) user.getProperty("email"));
Log.d("USER", user.getInnerJSONObject().toString());
JSONObject details = user.getInnerJSONObject();
useremail = details.optString("email");
Log.d("name", user.getName());
Log.d("email", useremail);
}
}
});
}
}
});
}catch(NoClassDefFoundError e){
e.printStackTrace();
}
Try this one:
if you have object of user than do below:
if (user != null) {
String UserId = user.getId();
try {
Log.i("Birthdate", ""+user.getInnerJSONObject().getString("birthday"));
} catch (JSONException e) {
e.printStackTrace();
}
}