I'm developping an app that uses this : https://developers.facebook.com/docs/android/native-login/
I have followed the Facebook dev tutorial, so basically I have the session check, it opens the dialog, and I'm trying to get the Cancel event (when the user cancel the facebook dialog) but I have no method on this.
Maybe you can help.
Thanks
EDIT: Actually, even if I click the cancel button, I still receive the GraphUser correctly. That's weird.
With Android SDK 3.5, I got the cancel event via exception, if the state change callback with instance of FacebookOperationCanceledException or FacebookAuthorizationException, its an cancel event:
private void onSessionStateChange(Session session, SessionState state, Exception exception) {
if (exception instanceof FacebookOperationCanceledException || exception instanceof FacebookAuthorizationException) {
// Cancelled by user, show alert
new AlertDialog.Builder(this).setTitle(R.string.cancelled).setMessage(R.string.permission_not_granted).setPositiveButton(R.string.ok, null).show();
} else {
Session session = Session.getActiveSession();
if ((session != null && session.isOpened())) {
// Session ready
}
}
}
private Session.StatusCallback callback = new Session.StatusCallback() {
#Override
public void call(Session session, SessionState state, Exception exception) {
onSessionStateChange(session, state, exception);
}
};
It works just great
Add a Session.StatusCallback to your open request where you can check the SessionState.
new Session.StatusCallback() {
#Override
public void call(Session session, SessionState state, Exception exception) {
//check state
}
};
Check out this question.
Related
I did the following:
#Override
public void onResume() {
super.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);
}
uiHelper.onResume();
}
and
private void onSessionStateChange(Session session, SessionState state, Exception exception) {
if (state.isOpened()) {
makeMeRequest(session);
} else if (state.isClosed()) {
}
}
and
private void makeMeRequest(final Session session) {
Request request = Request.newMeRequest(session, new Request.GraphUserCallback() {
#Override
public void onCompleted(GraphUser user, Response response) {
if (session == Session.getActiveSession()) {
if (user != null) {
log.d("creating fragment"); //<<<<<<<<<<<<<<<
//creating a fragment when the request is complete
.....
}
}
if (response.getError() != null) {
}
}
});
request.executeAsync();
}
Please read the comment of the first code clause: as suggested by Facebook, that code works because without it, the fragment is not created in certain scenarios even though I'm logged in, but with this code, onCompleted is called twice and I get an exception. see my logging in the 3rd code clause: log.d("creating fragment") - I see it twice before the exception occurred.
Any idea what am I missing?
p.s.: I have a main activity that calls a fragment where the user can login to facebook
Session session = Session.getActiveSession();
if (session != null && (session.isOpened() || session.isClosed())) {
onSessionStateChange(session, session.getState(), null);
}
don't use above code in onresume(),
Activity normally called first oncreate() and then onresume().so that it's called twice.
please check it.
I am trying to upload a picture to facebook using the sdk for android. When i run the code my app crashes. Can someone help me. I am not too sure how to use the sdk. Is there another way to upload pictures?
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_main);
bm = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
// start Facebook Login
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.newUploadPhotoRequest(session, bm, new Request.Callback() {
#Override
public void onCompleted(Response response)
{
// TODO Auto-generated method stub
if (isFinishing()) {
return;
}
if (response.getError() != null) { // [IF Failed Posting]
Log.d("", "photo upload problem. Error="+response.getError() );
} // [ENDIF Failed Posting]
Object graphResponse = response.getGraphObject().getProperty("id");
if (graphResponse == null || !(graphResponse instanceof String) ||
TextUtils.isEmpty((String) graphResponse)) { // [IF Failed upload/no results]
Log.d("", "failed photo upload/no response");
} else { // [ELSEIF successful upload]
fbPhotoAddress = "https://www.facebook.com/photo.php?fbid=" +graphResponse;
}
}
} ).executeAsync();
}
}
});
}
}
I am trying to see access_token in logcat but it's now showing up. Why?
private void updateUI() {
Session session = Session.getActiveSession();
Log.i("access_token", session.getAccessToken());
if ( user != null) {
profilePictureView.setProfileId(user.getId());
greeting.setText(getString(R.string.hello_user, user.getFirstName()));
accessToken.setText(session.getAccessToken());
} else {
profilePictureView.setProfileId(null);
greeting.setText(null);
accessToken.setText(null);
}
}
I'm trying to use the Facebook 3.0 SDK's login by following this guide from the facebook developer's:
https://developers.facebook.com/docs/tutorials/androidsdk/3.0/scrumptious/authenticate/
my problem is that when the user clicks the login button, my activity closes and Facebook's process dies.
this is the logcat from Android Studio:
08-20 12:17:40.124 353-353/system_process I/ActivityManager: START u0 {act=SSO_WITH_FALLBACK cmp=com.my.app/com.facebook.LoginActivity (has extras)} from pid 30362
08-20 12:17:40.434 353-370/system_process I/ActivityManager: Displayed com.my.app/com.facebook.LoginActivity: +268ms
08-20 12:17:44.094 353-546/system_process I/ActivityManager: Start proc android.process.acore for content provider com.android.providers.contacts/.ContactsProvider2: pid=30500 uid=10014 gids={50014, 3003, 1015, 1028}
08-20 12:17:44.134 30500-30500/android.process.acore E/Trace: error opening trace file: No such file or directory (2)
08-20 12:17:45.494 353-12974/system_process I/ActivityManager: Process com.facebook.katana:dash (pid 30233) has died.
Any suggestion on my problem?
EDIT:
Here's the code of the main activity
public class MainActivity extends FragmentActivity {
public static final boolean D = SystemConstants.ACTIVE_DEBUG;
public static final String TAG = "MainActivity";
private static final int SPLASH = 0;
private static final int SELECTION = 1;
private static final int FRAGMENT_COUNT = SELECTION +1;
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
protected 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);
FragmentTransaction transaction = fm.beginTransaction();
for (Fragment fragment : fragments) {
transaction.hide(fragment);
}
transaction.commit();
}
/**
* Configure files destinations.
*/
private void configureEnvironment() {
File sd = Environment.getExternalStorageDirectory();
if (sd.canWrite()) {
File destination = new File(sd, SettingConstants.BASE_DIR);
if (!destination.mkdir() && !destination.isDirectory()) {
Log.e(TAG, "Unable to create Base Directory.");
Tracking.sendException(new IllegalStateException("Unable to create Base Directory."));
}
File audio = new File(sd, SettingConstants.AUDIO_DIR);
if (!audio.mkdir() && !audio.isDirectory()) {
Log.e(TAG, "Unable to create Audio Directory.");
Tracking.sendException(new IllegalStateException("Unable to create Audio Directory."));
}
File avatar = new File(sd, SettingConstants.AVATAR_DIR);
if (!avatar.mkdir() && !avatar.isDirectory()) {
Log.e(TAG, "Unable to create Avatar Directory.");
Tracking.sendException(new IllegalStateException("Unable to create Avatar Directory."));
}
File image = new File(sd, SettingConstants.IMAGE_DIR);
if (!image.mkdir() && !image.isDirectory()) {
Log.e(TAG, "Unable to create Image Directory.");
Tracking.sendException(new IllegalStateException("Unable to create Image Directory."));
}
File video = new File(sd, SettingConstants.VIDEO_DIR);
if (!video.mkdir() && !video.isDirectory()) {
Log.e(TAG, "Unable to create Video Directory.");
Tracking.sendException(new IllegalStateException("Unable to create Video Directory."));
}
}
}
/**
* Shows a fragment
* #param fragmentIndex
* #param addToBackStack
*/
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();
}
/**
* called due to session state changes. The method shows the relevant fragment based on the person's authenticated state.
* #param session Facebook Session
* #param state Facebook login state
* #param exception Eventual exception
*/
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);
}
}
}
/**
* case where fragments are newly instantiated and the authenticated versus nonauthenticated UI needs to be properly set.
*/
#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);
}
}
#Override
protected void onStart() {
super.onStart();
Tracking.startActivityTracking(this);
}
#Override
protected void onStop() {
super.onStop();
Tracking.stopActivityTracking(this);
}
#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);
}
}
EDIT 2:
Tried on the emulator gives the same error, given that the facebook APK is not installed it shows a webview, asks for login and then closes the activity.
I've added method tracing logging, the last call inside MainActivity is onDestroy...
Just found the solution to this problem.
Make sure that you don't use
android:noHistory="true"
in the manifest, relative to the MainActivity (In the given sample).
I implemented Facebook SDK in my Android application. I am using the login function of the SDK. What i am trying to do is the following :
When MainActivity starts, check if there is an active session
If there isn't, give the user the chance to login into facebook
If there is, user has to be redirected to an other Activity (let's call this : HomeActivity).
When my application starts, it starts the MainActivity. My onCreate() method looks like this :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
this.app = (ApplicationClass)getApplicationContext();
app.setUiHelper(new UiLifecycleHelper(this, callback));
uiHelper = app.getUiHelper();
uiHelper.onCreate(savedInstanceState);
if(this.app.getLoggedIn()) {
setContentView(R.layout.login);
startLoggingIn(); // <-- Makes login button invisible and starts spinner
login();
} else {
setContentView(R.layout.login);
}
}
ApplicationClass is a class where i set all kind of information that can be used throughout the application lifecycle. It doesn't really matter but i thought i include it in the example.
So when MainActivity starts, it should call login() method, which looks like this :
public void login() {
logging_in = true;
Log.i(TAG, "Loggin in");
synchronized (this) {
// start Facebook Login
Session.openActiveSession(this, true, new Session.StatusCallback() {
// callback when session changes state
#Override
public void call(Session session, SessionState state, Exception exception) {
if (Session.getActiveSession().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) { // User is logged in
app.setUser(user);
app.setLoggedIn(true);
// Redirect user to the HomeActivity
Intent intent = new Intent(getBaseContext(), HomeActivity.class);
startActivity(intent);
}
}
});
}
}
});
logging_in = false;
}
}
And finally, my callback for Facebook session looks like this :
private void onSessionStateChange(Session session, SessionState state, Exception exception) {
if (state.isOpened()) {
synchronized (this) {
if( ! logging_in ) {
login();
}
}
} else if (state.isClosed()) {
setContentView(R.layout.login);
}
}
It does it all well, except the login() method gets called about many times. The output in my log is :
Why does it get called so many times? It obviously make sure the HomeActivity intent is started multiple times. I can't figure out why.
Solution
Changed my Session.StateCallback a little bit. It now looks like this :
private void onSessionStateChange(Session session, SessionState state, Exception exception) {
if (state.isOpened()) {
if(state == SessionState.OPENED_TOKEN_UPDATED) {
Log.i(TAG, "OPENED_TOKEN_UPDATED");
login();
} else if (state == SessionState.OPENED) {
if(app.getUser() != null) {
// Redirect user to the HomeActivity
Intent intent = new Intent(getBaseContext(), HomeActivity.class);
startActivity(intent);
} else {
login();
}
}
} else if (state.isClosed()) {
if(state == SessionState.CLOSED_LOGIN_FAILED) {
Log.i(TAG, "CLOSED_LOGIN_FAILED");
setContentView(R.layout.login);
} else if(state == SessionState.CLOSED) {
Log.i(TAG, "CLOSED");
//setContentView(R.layout.login);
}
}
}
Its most likely because you're calling login from onSessionState changed.
When you login what do think is going to happen to the session, it's going to change right.
And when it changes it calls onSessionState change and you call login.
I would expect that to loop infinitely but it seems Facebook have done some handling for this.
I also faced the same problem .. I just changed my activity result code . And it worked ..