Google Login connect Error
Android Code..
public class GooglePlusPlugin implements ConnectionCallbacks,
OnConnectionFailedListener{
Activity resultactivity;
private Activity activity;// activity is Unity3D currentActivity
public void init(String objName, String CallbackName) {
callbackName = CallbackName;
unityObjectName = objName;
mApiClient = new GoogleApiClient.Builder(activity, this, this)
.addApi(Plus.API).addScope(Plus.SCOPE_PLUS_LOGIN)
.addScope(Plus.SCOPE_PLUS_PROFILE).build();
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
resultactivity = new ResultActivity();
mConnectionProgressDialog = new ProgressDialog(activity);
mConnectionProgressDialog.setMessage("Signing in...");
}
});
}
#Override
public void onConnectionFailed(final ConnectionResult result) {
if (!mConnectionProgressDialog.isShowing()) {
if (result.hasResolution()) {
try {
result.startResolutionForResult(resultactivity,
result.getErrorCode());
return;
} catch (SendIntentException e) {
mApiClient.connect();
}
}
}
}
}
startResolutionForResult a call to onActivityResult
I try to use onActivityResult other activities, because not extends the activity in GooglePlusPlugin
public class ResultActivity extends FragmentActivity
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_RESOLVE_ERR
&& resultCode == RESULT_OK) {
GooglePlusPlugin.getInstance().reconnect(requestCode, resultCode);
finish();
}
}
but failed...
error is
Caused by: java.lang.NullPointerException
at android.app.Activity.startIntentSenderForResultInner(Activity.java:3560)
at android.app.Activity.startIntentSenderForResult(Activity.java:3536)
at android.app.Activity.startIntentSenderForResult(Activity.java:3503)
at com.google.android.gms.common.ConnectionResult.startResolutionForResult(Unknown Source)
at kr.co.crooz.plugin.googleplus.GooglePlusPlugin.onConnectionFailed(GooglePlusPlugin.java:212)
Why startIntentSenderForResult need, I do not know how to use it.
How to solve?
Thanks for reading long code
private Activity activity; Activity has already been taken from another part.
I like long content. The part that is not.
try {
this.unityPlayerClass = Class
.forName("com.unity3d.player.UnityPlayer");
this.unityPlayerActivityField = this.unityPlayerClass
.getField("currentActivity");
this.unitySendMessageMethod = this.unityPlayerClass.getMethod(
"UnitySendMessage", new Class[] { String.class,
String.class, String.class });
this.activity = getActivity();
}
private Activity getActivity() {
if (this.unityPlayerActivityField != null) {
try {
Activity activity = (Activity) this.unityPlayerActivityField
.get(this.unityPlayerClass);
if (activity == null) {
Log.d(TAG,
"Something has gone terribly wrong. The Unity Activity does not exist. This could be due to a low memory situation");
}
return activity;
} catch (Exception e) {
Log.d(TAG, "error getting currentActivity: " + e.getMessage());
}
}
return this.activity;
}
your Activity is null
private Activity activity;// activity is Unity3D currentActivity
you declare it here but you never grab the activity from unity3D as i guess you trying to do, this will result that you activity is null and will throw nullpointerexeption
Related
After having successfully followed the guide Accessing Google APIs, I am trying to move all the Google+ related code from my MainActivity to a separate custom GoogleFragment.
However I am stuck at the very last spot - in my custom Fragment, I don't know how to access the mResolvingError field after the DialogFragment has been dismissed:
public class GoogleFragment extends Fragment
implements GoogleApiClient.OnConnectionFailedListener {
private boolean mResolvingError = false; // HOW TO ACCESS?
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
if (mResolvingError) {
// Already attempting to resolve an error.
return;
} else if (connectionResult.hasResolution()) {
try {
mResolvingError = true;
connectionResult.startResolutionForResult(getActivity(), REQUEST_RESOLVE_ERROR);
} catch (IntentSender.SendIntentException e) {
// There was an error with the resolution intent. Try again.
if (mGoogleApiClient != null)
mGoogleApiClient.connect();
}
} else {
// Show dialog using GoogleApiAvailability.getErrorDialog()
showErrorDialog(connectionResult.getErrorCode());
mResolvingError = true;
}
}
private void showErrorDialog(int errorCode) {
// Create a fragment for the error dialog
ErrorDialogFragment dialogFragment = new ErrorDialogFragment();
// Pass the error that should be displayed
Bundle args = new Bundle();
args.putInt(ARGS_DIALOG_ERROR, errorCode);
dialogFragment.setArguments(args);
dialogFragment.show(getActivity().getSupportFragmentManager(), TAG_DIALOG_ERROR);
}
public static class ErrorDialogFragment extends DialogFragment {
public ErrorDialogFragment() {
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Get the error code and retrieve the appropriate dialog
int errorCode = this.getArguments().getInt(ARGS_DIALOG_ERROR);
return GoogleApiAvailability.getInstance().getErrorDialog(
this.getActivity(),
errorCode,
REQUEST_RESOLVE_ERROR);
}
#Override
public void onDismiss(DialogInterface dialog) {
mResolvingError = false; // DOES NOT COMPILE
}
}
}
What should I do here please?
If I make the ErrorDialogFragment non-static I get compile error:
This fragment inner class should be static
(GoogleFragment.ErrorDialogFragment)
If I keep it static - I can not access the variable either.
I am thinking of 2 workarounds for my problem:
Using LocalBroadcastManager to send a custom Intent from ErrorDialogFragment to GoogleFragment
Define a custom method in GoogleFragment and access it through getSupportFragmentManager().findFragmentByTag()
But is there maybe a simpler solution?
UPDATE:
I've changed the mResolvingError field to public and have tried this code:
#Override
public void onDismiss(DialogInterface dialog) {
GoogleFragment f = (GoogleFragment) getActivity().getSupportFragmentManager().findFragmentByTag(GoogleFragment.TAG);
if (f != null && f.isVisible()) {
f.mResolvingError = false;
}
}
but I am not sure how to test this properly and if f.isVisible() is needed there...
UPDATE 2:
Maybe I should somehow use DialogInterface.OnDismissListener with GoogleApiAvailability.getInstance().getErrorDialog in my code?
BladeCoder's comments have been very insightful, thanks.
However I have realized, that all the hassle with saving and restoring mResolvingError is unnecessary, because startResolutionForResult() starts a separate Activity anyway and obstructs my app - so it doesn't really matter if I rotate device or not.
Here is my final code to initiate GCM and fetch Google+ user data -
MainActivity.java:
public static final int REQUEST_GOOGLE_PLAY_SERVICES = 1972;
public static final int REQUEST_GOOGLE_PLUS_LOGIN = 2015;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null)
startRegistrationService();
}
private void startRegistrationService() {
GoogleApiAvailability api = GoogleApiAvailability.getInstance();
int code = api.isGooglePlayServicesAvailable(this);
if (code == ConnectionResult.SUCCESS) {
onActivityResult(REQUEST_GOOGLE_PLAY_SERVICES, Activity.RESULT_OK, null);
} else if (api.isUserResolvableError(code) &&
api.showErrorDialogFragment(this, code, REQUEST_GOOGLE_PLAY_SERVICES)) {
// wait for onActivityResult call (see below)
} else {
String str = GoogleApiAvailability.getInstance().getErrorString(code);
Toast.makeText(this, str, Toast.LENGTH_LONG).show();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch(requestCode) {
case REQUEST_GOOGLE_PLAY_SERVICES:
if (resultCode == Activity.RESULT_OK) {
Intent i = new Intent(this, RegistrationService.class);
startService(i); // OK, init GCM
}
break;
case REQUEST_GOOGLE_PLUS_LOGIN:
if (resultCode == Activity.RESULT_OK) {
GoogleFragment f = (GoogleFragment) getSupportFragmentManager().
findFragmentByTag(GoogleFragment.TAG);
if (f != null && f.isVisible())
f.onActivityResult(requestCode, resultCode, data);
}
break;
default:
super.onActivityResult(requestCode, resultCode, data);
}
}
GoogleFragment.java:
public class GoogleFragment extends Fragment
implements View.OnClickListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
public final static String TAG = "GoogleFragment";
private GoogleApiClient mGoogleApiClient;
private ImageButton mLoginButton;
private ImageButton mLogoutButton;
public GoogleFragment() {
// required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_google, container, false);
mGoogleApiClient = new GoogleApiClient.Builder(getContext())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(Plus.API)
.addScope(Plus.SCOPE_PLUS_PROFILE)
.build();
mLoginButton = (ImageButton) v.findViewById(R.id.login_button);
mLoginButton.setOnClickListener(this);
mLogoutButton = (ImageButton) v.findViewById(R.id.logout_button);
mLogoutButton.setOnClickListener(this);
return v;
}
private void googleLogin() {
mGoogleApiClient.connect();
}
private void googleLogout() {
if (mGoogleApiClient.isConnecting() || mGoogleApiClient.isConnected())
mGoogleApiClient.disconnect();
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK)
mGoogleApiClient.connect();
}
#Override
public void onClick(View v) {
if (v == mLoginButton)
googleLogin();
else
googleLogout();
}
#Override
public void onConnected(Bundle bundle) {
Person me = Plus.PeopleApi.getCurrentPerson(mGoogleApiClient);
if (me != null) {
String id = me.getId();
Person.Name name = me.getName();
String given = name.getGivenName();
String family = name.getFamilyName();
boolean female = (me.hasGender() && me.getGender() == 1);
String photo = null;
if (me.hasImage() && me.getImage().hasUrl()) {
photo = me.getImage().getUrl();
photo = photo.replaceFirst("\\bsz=\\d+\\b", "sz=300");
}
String city = "Unknown city";
List<Person.PlacesLived> places = me.getPlacesLived();
if (places != null) {
for (Person.PlacesLived place : places) {
city = place.getValue();
if (place.isPrimary())
break;
}
}
Toast.makeText(getContext(), "Given: " + given + ", Family: " + family + ", Female: " + female + ", City: " + city, Toast.LENGTH_LONG).show();
}
}
#Override
public void onConnectionSuspended(int i) {
// ignore? don't know what to do here...
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
if (connectionResult.hasResolution()) {
try {
connectionResult.startResolutionForResult(getActivity(), MainActivity.REQUEST_GOOGLE_PLUS_LOGIN);
} catch (IntentSender.SendIntentException e) {
mGoogleApiClient.connect();
}
} else {
int code = connectionResult.getErrorCode();
String str = GoogleApiAvailability.getInstance().getErrorString(code);
Toast.MakeText(getContext(), str, Toast.LENGTH_LONG).show();
}
}
}
here is the code provided by the official guide, while this is a snippet causing problems.
#Override
public void onConnectionFailed(ConnectionResult result) {
if (mResolvingError) {
// Already attempting to resolve an error.
return;
} else if (result.hasResolution()) {
try {
mResolvingError = true;
result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
} catch (IntentSender.SendIntentException e) {
// There was an error with the resolution intent. Try again.
mGoogleApiClient.connect();
}
} else {
// Show dialog using GooglePlayServicesUtil.getErrorDialog()
mResolvingError = true;
GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(), this, REQUEST_RESOLVE_ERROR)
.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
mResolvingError = false;
}
});
}
}
If I use it in a Service, when you read the variable this passed as argument to those functions, they expect an Activity type.
How should I do? It's a Service.
For the same reason I can't get activity result
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_RESOLVE_ERROR) {
mResolvingError = false;
if (resultCode == RESULT_OK) {
// Make sure the app is not already connected or attempting to connect
if (!mGoogleApiClient.isConnecting() &&
!mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
}
}
}
}
This answer assumes your service is a "started" service. If it is a bound service or intent service, indicate that in a comment and I'll update the description and code included here.
The solution I suggest is to implement the activity shown below to handle the resolution UI. Replace the onConnectionFailed() method in your service with this code to hand off the resolution processing to the ResolverActivity:
#Override
public void onConnectionFailed(ConnectionResult result) {
Intent i = new Intent(this, ResolverActivity.class);
i.putExtra(ResolverActivity.CONNECT_RESULT_KEY, result);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
}
Add the activity shown below to your app. When the connection request in your service fails, the connection result, which is a Parcelable, is passed to the activity. The activity handles the resolution UI and when finished, returns the status to the service as an intent extra. You will need to modify the code in your service's onStartCommand() to examine the extras in the intent to determine if it is being called to start the service for the first time, or to receive resolution status from the ResolverActivity.
An enhancement to this approach would be to post a notification with a PendingIntent for ResolverActivity instead of launching the activity immediately. That would give the user the option of deferring resolution of the connection failure.
public class ResolverActivity extends AppCompatActivity {
public static final String TAG = "ResolverActivity";
public static final String CONNECT_RESULT_KEY = "connectResult";
public static final String CONN_STATUS_KEY = "connectionStatus";
public static final int CONN_SUCCESS = 1;
public static final int CONN_FAILED = 2;
public static final int CONN_CANCELLED = 3;
// Request code to use when launching the resolution activity
private static final int REQUEST_RESOLVE_ERROR = 1111;
private static final String ERROR_CODE_KEY = "errorCode";
private static final String DIALOG_FRAG_TAG = "errorDialog";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate()");
// No content needed.
//setContentView(R.layout.activity_main);
Intent i = getIntent();
ConnectionResult result = i.getParcelableExtra(CONNECT_RESULT_KEY);
if (result.hasResolution()) {
try {
Log.i(TAG, "Starting error resolution...");
result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
} catch (IntentSender.SendIntentException e) {
// There was an error with the resolution intent.
sendStatusToService(CONN_FAILED);
finish();
}
} else {
// Show dialog using GooglePlayServicesUtil.getErrorDialog()
ErrorDialogFragment.newInstance(result.getErrorCode())
.show(getSupportFragmentManager(), DIALOG_FRAG_TAG);
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent result) {
if (requestCode == REQUEST_RESOLVE_ERROR) {
if (resultCode == RESULT_OK) {
Log.i(TAG, "onActivityResult(): Connection problem resolved");
sendStatusToService(CONN_SUCCESS);
} else {
sendStatusToService(CONN_CANCELLED);
Log.w(TAG, "onActivityResult(): Resolution cancelled");
}
// Nothing more to do in this activity
finish();
}
}
private void sendStatusToService(int status) {
Intent i = new Intent(this, MyGoogleApiService.class);
i.putExtra(CONN_STATUS_KEY, status);
startService(i);
}
// Fragment to display an error dialog
public static class ErrorDialogFragment extends DialogFragment {
public static ErrorDialogFragment newInstance(int errorCode) {
ErrorDialogFragment f = new ErrorDialogFragment();
// Pass the error that should be displayed
Bundle args = new Bundle();
args.putInt(ERROR_CODE_KEY, errorCode);
f.setArguments(args);
return f;
}
#Override
#NonNull
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Get the error code and retrieve the appropriate dialog
int errorCode = getArguments().getInt(ERROR_CODE_KEY);
return GooglePlayServicesUtil.getErrorDialog(
errorCode, getActivity(), REQUEST_RESOLVE_ERROR);
}
#Override
public void onDismiss(DialogInterface dialog) {
Log.i(TAG, "Dialog dismissed");
}
}
}
Update
I used Session class as told. But still, i dont think its working. below is my code:
But still, my edittext is not updated with name. it is showing You are not logged in. Neither any of the log messages in the Session.CallBack method are shown in my logcat
public class profile extends Activity implements View.OnClickListener {
ImageView profilePropic;
EditText name;
Dialog dialog;
Button gallery;
Bitmap bmp;
FileOutputStream fos;
LoginButton loginButton;
private UiLifecycleHelper uiHelper;
private static final List<String> PERMISSIONS = Arrays.asList("publish_actions");
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.profile);
uiHelper = new UiLifecycleHelper(this, statusCallback);
uiHelper.onCreate(savedInstanceState);
name = (EditText) findViewById(R.id.profile_name);
profilePropic = (ImageView) findViewById(R.id.profile_propic);
loginButton = (LoginButton) findViewById(R.id.fb_login_button);
loginButton.setUserInfoChangedCallback(new LoginButton.UserInfoChangedCallback() {
#Override
public void onUserInfoFetched(GraphUser user) {
if (user != null) {
name.setText("Hello, " + user.getName());
} else {
name.setText("You are not logged");
}
}
});
}
private Session.StatusCallback statusCallback = new Session.StatusCallback() {
#Override
public void call(Session session, SessionState state, Exception exception) {
if (state.isOpened()) {
Log.d("FacebookSampleActivity", "Facebook session opened");
} else if (state.isClosed()) {
Log.d("FacebookSampleActivity", "Facebook session closed");
}
}
};
private void beginCrop(Uri source) {
Uri outputUri = Uri.fromFile(new File(getCacheDir(), "cropped"));
new Crop(source).output(outputUri).asSquare().start(this);
}
private void handleCrop(int resultCode, Intent result) {
if (resultCode == RESULT_OK) {
Uri uri = Crop.getOutput(result);
Picasso.with(this).load(uri).into(profilePropic);
try {
bmp = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
} catch (IOException e) {
e.printStackTrace();
}
try {
fos = openFileOutput("ProPic", Context.MODE_PRIVATE);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
bmp.compress(Bitmap.CompressFormat.JPEG, 60, fos);
} else if (resultCode == Crop.RESULT_ERROR) {
Toast.makeText(this, Crop.getError(result).getMessage(), Toast.LENGTH_SHORT).show();
}
}
#Override
protected void onResume() {
super.onResume();
uiHelper.onResume();
FileInputStream fis;
try {
fis = openFileInput("ProPic");
Bitmap bitmapA = BitmapFactory.decodeStream(fis);
profilePropic.setImageBitmap(bitmapA);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public void changeAvatar(View view) {
// Intent pickFromGallery = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
// startActivityForResult(pickFromGallery, OpenGallery);
dialog = new Dialog(this);
dialog.setContentView(R.layout.propic_dialog);
dialog.setTitle("Show us how you look like !");
dialog.show();
gallery = (Button) dialog.findViewById(R.id.gallery);
gallery.setOnClickListener(this);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == Crop.REQUEST_PICK && resultCode == RESULT_OK) {
beginCrop(data.getData());
} else if (requestCode == Crop.REQUEST_CROP) {
handleCrop(resultCode, data);
}
}
#Override
public void onClick(View v) {
if (v == gallery) {
Crop.pickImage(this);
dialog.dismiss();
}
}
public boolean checkPermissions() {
Session s = Session.getActiveSession();
if (s != null) {
return s.getPermissions().contains("publish_actions");
} else
return false;
}
public void requestPermissions() {
Session s = Session.getActiveSession();
if (s != null)
s.requestNewPublishPermissions(new Session.NewPermissionsRequest(
this, PERMISSIONS));
}
#Override
public void onPause() {
super.onPause();
uiHelper.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
uiHelper.onDestroy();
}
#Override
public void onSaveInstanceState(Bundle savedState) {
super.onSaveInstanceState(savedState);
uiHelper.onSaveInstanceState(savedState);
}
}
I haver researched on this tipic for quite a while.
What I came across is that in many tutorials
Facebook fb = new Facebook(App_Id);
is used while in many other sites, it is said that Facebook class is now deprecated. In facebook developers page also, Session class is used. What is that and how to use that?
This is my first app. If any one guide me with complete detail about this concept, it will be greatful for me.
Thank You
THIS CLASS SHOULD BE CONSIDERED DEPRECATED.
All public members of this class are intentionally deprecated. New code should instead use Session to manage session state, Request to make API requests, and WebDialog to make dialog requests.
Adding #Deprecated to this class causes warnings in other deprecated classes that reference this one. That is the only reason this entire class is not deprecated.
Read below document regarding deprecation :-
https://developers.facebook.com/docs/reference/android/current/class/Facebook/
Update your sdk of facebook from below link :-
https://developers.facebook.com/docs/android/upgrading
I am trying to integrate an android app with the the new facebook 3.0 api, but I get this exception:
java.lang.RuntimeException: Unable to resume activity
{dk.imu.konnekt/com.facebook.LoginActivity}:
com.facebook.FacebookException: Cannot call LoginActivity with a null
calling package. This can occur if the launchMode of the caller is
singleInstance.
I have search for this error but no one else seems to have had any troble with it. I guess it is because I am using a TabHost and TabsGroupActivities for each tab. But I have no clue on how to solve it.
I have added the relevant code here:
public class MainTabActivity extends TabActivity {
public void onCreate(Bundle savedInstanteState){
super.onCreate(savedInstanteState);
setContentView(R.layout.tab_layout);
TabHost tabHost = getTabHost();
View shareTab = getLayoutInflater().inflate(R.layout.share_tab, null);
tabHost.addTab(tabHost.newTabSpec("Share").setIndicator(shareTab)
.setContent(new Intent(MainTabActivity.this, ShareGroupActivity.class)));
...
}
}
-
public class ShareGroupActivity extends TabsGroupActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startChildActivity("ShareActivity", new Intent(this, ShareActivity.class));
}
}
-
public class ShareActivity extends BaseActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.share);
testFacebookConnection();
}
public void testFacebookConnection(){
Session session = new Session(this);
Session.setActiveSession(session);
SessionState state = session.getState();
Settings.addLoggingBehavior(LoggingBehavior.INCLUDE_ACCESS_TOKENS);
Session.StatusCallback statusCallback =
new Session.StatusCallback() {
#Override
public void call(Session session, SessionState state, Exception exception) {
Toast.makeText(ShareActivity.this, "Facebook session status changed", Toast.LENGTH_SHORT).show();
}
};
if (!session.isOpened() && !session.isClosed() && session.getState() != SessionState.OPENING) {
OpenRequest open = new OpenRequest(this).setCallback(statusCallback);
List<String> permission = new ArrayList<String>();
permission.add("publish_actions");
open.setPermissions(permission);
session.openForPublish(open);
} else {
Session.openActiveSession(this, true, statusCallback);
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data);
}
}
Any clue on how to solve it?
Update 1 stack trace:
FATAL EXCEPTION: main java.lang.RuntimeException: Unable to resume
activity {dk.imu.konnekt/com.facebook.LoginActivity}:
com.facebook.FacebookException: Cannot call LoginActivity with a null
calling package. This can occur if the launchMode of the caller is
singleInstance. at
android.app.ActivityThread.performResumeActivity(ActivityThread.java:2812)
at
android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2851)
at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2234)
at android.app.ActivityThread.access$600(ActivityThread.java:139) at
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1261)
at android.os.Handler.dispatchMessage(Handler.java:99)
android.os.Looper.loop(Looper.java:154) at
android.app.ActivityThread.main(ActivityThread.java:4945) at
java.lang.reflect.Method.invokeNative(Native Method) at
java.lang.reflect.Method.invoke(Method.java:511) at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) at
dalvik.system.NativeStart.main(Native Method) Caused by:
com.facebook.FacebookException: Cannot call LoginActivity with a null
calling package. This can occur if the launchMode of the caller is
singleInstance. at
com.facebook.LoginActivity.onResume(LoginActivity.java:110) at
android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1236)
at android.app.Activity.performResume(Activity.java:4613) at
android.app.ActivityThread.performResumeActivity(ActivityThread.java:2796)
... 12 more
Update 2:
I looked through the code and found the implementation of startChildActivity:
public void startChildActivity(String Id, Intent intent) {
Window window = getLocalActivityManager().startActivity(Id,intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
if (window != null) {
mIdList.add(Id);
setContentView(window.getDecorView());
}
}
It uses the flag FLAG_ACTIVITY_CLEAR_TOP. I tried to remove it, but no change in the outcome.
Update 3:
https://github.com/facebook/facebook-android-sdk/blob/master/facebook/src/com/facebook/LoginActivity.java
The Facebook code uses
callingPackage = getCallingPackage();
and
if (callingPackage == null) {
throw new FacebookException(NULL_CALLING_PKG_ERROR_MSG);
}
http://developer.android.com/reference/android/app/Activity.html#getCallingPackage()
This method has a note:
If the calling activity is not expecting a result (that is it did not
use the startActivityForResult(Intent, int) form that includes a
request code), then the calling package will be null.
In the method startChildActivity I use the getLocalActivityManager().startActivity, in TabsGroupActivity that extends ActivityGroup, to handle tab activities.
http://developer.android.com/reference/android/app/LocalActivityManager.html#startActivity(java.lang.String, android.content.Intent)
This method does not what the notes says. It does not expect a result and does not use the startActivityForResult method. The method also ensures something similar to singleinstance launchmode.
How should I change this method implementation, so it can work with facebook?
I managed to find my problem. Although I wasn't setting
android:launchMode="singleTask"
my LoginActivity had
android:noHistory="true"
which results in that exception. I put noHistory true because I didn't want the user to be able to press back button on the first activity after login and go back to login screen. Now I need to find another solution.
After lots of searching I figured out that there don't seems to be a way to startActivityForResult with LocalActivityManager used in the tabs.
So I ended up accepting that it will need an activity filling the entire screen. The activity is only shown a second or so with good network connection - I have made it with a republish option on errors also..
Start publish activity:
Intent intent = new Intent(this, FacebookShareActivity.class);
intent.putExtra(Constants.FACEBOOK_MESSAGE, shareMessage.getMessage());
startActivityForResult(intent, 1);
Facebook share activity code - publishing to users wall:
public class FacebookShareActivity extends Activity {
String message;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.facebook_publishing);
message = getIntent().getExtras().getString(Constants.FACEBOOK_MESSAGE);
createFacebookConnection();
}
public void republishButton_Click(View view){
setVisibilityForRepublishButton(false);
createFacebookConnection();
}
public void createFacebookConnection() {
Session session = new Session(this);
Session.setActiveSession(session);
Settings.addLoggingBehavior(LoggingBehavior.INCLUDE_ACCESS_TOKENS);
Session.StatusCallback statusCallback = new Session.StatusCallback() {
#Override
public void call(Session session, SessionState state, Exception exception) {
String message = "Facebook session status changed - " + session.getState() + " - Exception: " + exception;
//Toast.makeText(FacebookShareActivity.this, message, Toast.LENGTH_SHORT).show();
Log.w("Facebook test", message);
if (session.isOpened() || session.getPermissions().contains("publish_actions")) {
publishToWall();
} else if (session.isOpened()) {
OpenRequest open = new OpenRequest(FacebookShareActivity.this).setCallback(this);
List<String> permission = new ArrayList<String>();
permission.add("publish_actions");
open.setPermissions(permission);
Log.w("Facebook test", "Open for publish");
session.openForPublish(open);
}
}
};
if (!session.isOpened() && !session.isClosed() && session.getState() != SessionState.OPENING) {
session.openForRead(new Session.OpenRequest(this).setCallback(statusCallback));
} else {
Log.w("Facebook test", "Open active session");
Session.openActiveSession(this, true, statusCallback);
}
}
private void setVisibilityForRepublishButton(Boolean visible) {
((Button) findViewById(R.id.republishButton)).setVisibility(visible ? View.VISIBLE : View.GONE);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data);
//Toast.makeText(FacebookShareActivity.this, "onActivityResult", Toast.LENGTH_SHORT).show();
}
void publishToWall() {
Session session = Session.getActiveSession();
Bundle postParams = new Bundle();
postParams.putString("message", message);
final Context context = this;
Request.Callback callback = new Request.Callback() {
public void onCompleted(Response response) {
FacebookRequestError error = response.getError();
if (error != null) {
setVisibilityForRepublishButton(true);
Toast.makeText(context, error.getErrorMessage(), Toast.LENGTH_SHORT).show();
} else {
JSONObject graphResponse = response.getGraphObject().getInnerJSONObject();
String postId = null;
try {
postId = graphResponse.getString("id");
} catch (JSONException e) {
setVisibilityForRepublishButton(true);
Log.i("Facebook error", "JSON error " + e.getMessage());
}
//Toast.makeText(context, postId, Toast.LENGTH_LONG).show();
finish();
}
}
};
Request request = new Request(Session.getActiveSession(), "me/feed", postParams, HttpMethod.POST, callback);
RequestAsyncTask task = new RequestAsyncTask(request);
task.execute();
}
}
I've got the same problem : trying to log into facebook, with the dialog provided inside the SDK, but from an activity that was itself inside a tabgroup ; like ShareActivity above.
What I've done is basically called startActivityForResult on parent activity of ShareActivity (that is ShareGroupActivity), instead of calling it on ShareActivity.
So 1 , add this in ShareGroupActivity :
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
System.out.println("facebook status called");
super.onActivityResult(requestCode, resultCode, data);
Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data);
}
2 you need to modify the class Session, inside FacebookSDK project, under src com.facebook
2.1 add a boolean member
public boolean insideTabGroup;
2.2 modify StartActivityDelegate, that is used by session to open login ; add the boolean as parameter
interface StartActivityDelegate {
public void startActivityForResult(Intent intent, int requestCode, boolean insideTabGroup);
public Activity getActivityContext();
}
2.3 inside the inner class AuthorizationRequest, modify the implementation of this delegate :
AuthorizationRequest(final Activity activity) {
startActivityDelegate = new StartActivityDelegate() {
#Override
public void startActivityForResult(Intent intent, int requestCode, boolean insideTabGroup) {
if(insideTabGroup) {
ActivityGroup parentActivity = (ActivityGroup) activity.getParent();
parentActivity.startActivityForResult(intent,requestCode);
} else {
activity.startActivityForResult(intent, requestCode);
}
}
#Override
public Activity getActivityContext() {
return activity;
}
};
}
2.4 Also, modify the other constructors of AuthorizationRequest, by just adding the boolean parameter. As I do not use login to facebook from somewhere else than an activity, that's ok.
2.5 Modifiy the tryLoginActivity method of Session class, to use the boolean member as a parameter :
private boolean tryLoginActivity(AuthorizationRequest request) {
Intent intent = getLoginActivityIntent(request);
if (!resolveIntent(intent)) {
return false;
}
try {
request.getStartActivityDelegate().startActivityForResult(intent, request.getRequestCode(),this.insideTabGroup);
} catch (ActivityNotFoundException e) {
return false;
}
return true;
}
3 Set the boolean member in the session :
Session session = Session.getActiveSession();
session.insideTabGroup = true;
That should do the trick.
Cdt
I had this same error with the Parse.com Facebook SDK integration and was down to me missing the call to ParseFacebookUtils.finishAuthentication which is noted in the docs.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
ParseFacebookUtils.finishAuthentication(requestCode, resultCode, data);
}
I am trying to integrate an android app with the the new facebook 3.0 api, but I get this exception:
java.lang.RuntimeException: Unable to resume activity
{dk.imu.konnekt/com.facebook.LoginActivity}:
com.facebook.FacebookException: Cannot call LoginActivity with a null
calling package. This can occur if the launchMode of the caller is
singleInstance.
I have search for this error but no one else seems to have had any troble with it. I guess it is because I am using a TabHost and TabsGroupActivities for each tab. But I have no clue on how to solve it.
I have added the relevant code here:
public class MainTabActivity extends TabActivity {
public void onCreate(Bundle savedInstanteState){
super.onCreate(savedInstanteState);
setContentView(R.layout.tab_layout);
TabHost tabHost = getTabHost();
View shareTab = getLayoutInflater().inflate(R.layout.share_tab, null);
tabHost.addTab(tabHost.newTabSpec("Share").setIndicator(shareTab)
.setContent(new Intent(MainTabActivity.this, ShareGroupActivity.class)));
...
}
}
-
public class ShareGroupActivity extends TabsGroupActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startChildActivity("ShareActivity", new Intent(this, ShareActivity.class));
}
}
-
public class ShareActivity extends BaseActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.share);
testFacebookConnection();
}
public void testFacebookConnection(){
Session session = new Session(this);
Session.setActiveSession(session);
SessionState state = session.getState();
Settings.addLoggingBehavior(LoggingBehavior.INCLUDE_ACCESS_TOKENS);
Session.StatusCallback statusCallback =
new Session.StatusCallback() {
#Override
public void call(Session session, SessionState state, Exception exception) {
Toast.makeText(ShareActivity.this, "Facebook session status changed", Toast.LENGTH_SHORT).show();
}
};
if (!session.isOpened() && !session.isClosed() && session.getState() != SessionState.OPENING) {
OpenRequest open = new OpenRequest(this).setCallback(statusCallback);
List<String> permission = new ArrayList<String>();
permission.add("publish_actions");
open.setPermissions(permission);
session.openForPublish(open);
} else {
Session.openActiveSession(this, true, statusCallback);
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data);
}
}
Any clue on how to solve it?
Update 1 stack trace:
FATAL EXCEPTION: main java.lang.RuntimeException: Unable to resume
activity {dk.imu.konnekt/com.facebook.LoginActivity}:
com.facebook.FacebookException: Cannot call LoginActivity with a null
calling package. This can occur if the launchMode of the caller is
singleInstance. at
android.app.ActivityThread.performResumeActivity(ActivityThread.java:2812)
at
android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2851)
at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2234)
at android.app.ActivityThread.access$600(ActivityThread.java:139) at
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1261)
at android.os.Handler.dispatchMessage(Handler.java:99)
android.os.Looper.loop(Looper.java:154) at
android.app.ActivityThread.main(ActivityThread.java:4945) at
java.lang.reflect.Method.invokeNative(Native Method) at
java.lang.reflect.Method.invoke(Method.java:511) at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) at
dalvik.system.NativeStart.main(Native Method) Caused by:
com.facebook.FacebookException: Cannot call LoginActivity with a null
calling package. This can occur if the launchMode of the caller is
singleInstance. at
com.facebook.LoginActivity.onResume(LoginActivity.java:110) at
android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1236)
at android.app.Activity.performResume(Activity.java:4613) at
android.app.ActivityThread.performResumeActivity(ActivityThread.java:2796)
... 12 more
Update 2:
I looked through the code and found the implementation of startChildActivity:
public void startChildActivity(String Id, Intent intent) {
Window window = getLocalActivityManager().startActivity(Id,intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
if (window != null) {
mIdList.add(Id);
setContentView(window.getDecorView());
}
}
It uses the flag FLAG_ACTIVITY_CLEAR_TOP. I tried to remove it, but no change in the outcome.
Update 3:
https://github.com/facebook/facebook-android-sdk/blob/master/facebook/src/com/facebook/LoginActivity.java
The Facebook code uses
callingPackage = getCallingPackage();
and
if (callingPackage == null) {
throw new FacebookException(NULL_CALLING_PKG_ERROR_MSG);
}
http://developer.android.com/reference/android/app/Activity.html#getCallingPackage()
This method has a note:
If the calling activity is not expecting a result (that is it did not
use the startActivityForResult(Intent, int) form that includes a
request code), then the calling package will be null.
In the method startChildActivity I use the getLocalActivityManager().startActivity, in TabsGroupActivity that extends ActivityGroup, to handle tab activities.
http://developer.android.com/reference/android/app/LocalActivityManager.html#startActivity(java.lang.String, android.content.Intent)
This method does not what the notes says. It does not expect a result and does not use the startActivityForResult method. The method also ensures something similar to singleinstance launchmode.
How should I change this method implementation, so it can work with facebook?
I managed to find my problem. Although I wasn't setting
android:launchMode="singleTask"
my LoginActivity had
android:noHistory="true"
which results in that exception. I put noHistory true because I didn't want the user to be able to press back button on the first activity after login and go back to login screen. Now I need to find another solution.
After lots of searching I figured out that there don't seems to be a way to startActivityForResult with LocalActivityManager used in the tabs.
So I ended up accepting that it will need an activity filling the entire screen. The activity is only shown a second or so with good network connection - I have made it with a republish option on errors also..
Start publish activity:
Intent intent = new Intent(this, FacebookShareActivity.class);
intent.putExtra(Constants.FACEBOOK_MESSAGE, shareMessage.getMessage());
startActivityForResult(intent, 1);
Facebook share activity code - publishing to users wall:
public class FacebookShareActivity extends Activity {
String message;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.facebook_publishing);
message = getIntent().getExtras().getString(Constants.FACEBOOK_MESSAGE);
createFacebookConnection();
}
public void republishButton_Click(View view){
setVisibilityForRepublishButton(false);
createFacebookConnection();
}
public void createFacebookConnection() {
Session session = new Session(this);
Session.setActiveSession(session);
Settings.addLoggingBehavior(LoggingBehavior.INCLUDE_ACCESS_TOKENS);
Session.StatusCallback statusCallback = new Session.StatusCallback() {
#Override
public void call(Session session, SessionState state, Exception exception) {
String message = "Facebook session status changed - " + session.getState() + " - Exception: " + exception;
//Toast.makeText(FacebookShareActivity.this, message, Toast.LENGTH_SHORT).show();
Log.w("Facebook test", message);
if (session.isOpened() || session.getPermissions().contains("publish_actions")) {
publishToWall();
} else if (session.isOpened()) {
OpenRequest open = new OpenRequest(FacebookShareActivity.this).setCallback(this);
List<String> permission = new ArrayList<String>();
permission.add("publish_actions");
open.setPermissions(permission);
Log.w("Facebook test", "Open for publish");
session.openForPublish(open);
}
}
};
if (!session.isOpened() && !session.isClosed() && session.getState() != SessionState.OPENING) {
session.openForRead(new Session.OpenRequest(this).setCallback(statusCallback));
} else {
Log.w("Facebook test", "Open active session");
Session.openActiveSession(this, true, statusCallback);
}
}
private void setVisibilityForRepublishButton(Boolean visible) {
((Button) findViewById(R.id.republishButton)).setVisibility(visible ? View.VISIBLE : View.GONE);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data);
//Toast.makeText(FacebookShareActivity.this, "onActivityResult", Toast.LENGTH_SHORT).show();
}
void publishToWall() {
Session session = Session.getActiveSession();
Bundle postParams = new Bundle();
postParams.putString("message", message);
final Context context = this;
Request.Callback callback = new Request.Callback() {
public void onCompleted(Response response) {
FacebookRequestError error = response.getError();
if (error != null) {
setVisibilityForRepublishButton(true);
Toast.makeText(context, error.getErrorMessage(), Toast.LENGTH_SHORT).show();
} else {
JSONObject graphResponse = response.getGraphObject().getInnerJSONObject();
String postId = null;
try {
postId = graphResponse.getString("id");
} catch (JSONException e) {
setVisibilityForRepublishButton(true);
Log.i("Facebook error", "JSON error " + e.getMessage());
}
//Toast.makeText(context, postId, Toast.LENGTH_LONG).show();
finish();
}
}
};
Request request = new Request(Session.getActiveSession(), "me/feed", postParams, HttpMethod.POST, callback);
RequestAsyncTask task = new RequestAsyncTask(request);
task.execute();
}
}
I've got the same problem : trying to log into facebook, with the dialog provided inside the SDK, but from an activity that was itself inside a tabgroup ; like ShareActivity above.
What I've done is basically called startActivityForResult on parent activity of ShareActivity (that is ShareGroupActivity), instead of calling it on ShareActivity.
So 1 , add this in ShareGroupActivity :
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
System.out.println("facebook status called");
super.onActivityResult(requestCode, resultCode, data);
Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data);
}
2 you need to modify the class Session, inside FacebookSDK project, under src com.facebook
2.1 add a boolean member
public boolean insideTabGroup;
2.2 modify StartActivityDelegate, that is used by session to open login ; add the boolean as parameter
interface StartActivityDelegate {
public void startActivityForResult(Intent intent, int requestCode, boolean insideTabGroup);
public Activity getActivityContext();
}
2.3 inside the inner class AuthorizationRequest, modify the implementation of this delegate :
AuthorizationRequest(final Activity activity) {
startActivityDelegate = new StartActivityDelegate() {
#Override
public void startActivityForResult(Intent intent, int requestCode, boolean insideTabGroup) {
if(insideTabGroup) {
ActivityGroup parentActivity = (ActivityGroup) activity.getParent();
parentActivity.startActivityForResult(intent,requestCode);
} else {
activity.startActivityForResult(intent, requestCode);
}
}
#Override
public Activity getActivityContext() {
return activity;
}
};
}
2.4 Also, modify the other constructors of AuthorizationRequest, by just adding the boolean parameter. As I do not use login to facebook from somewhere else than an activity, that's ok.
2.5 Modifiy the tryLoginActivity method of Session class, to use the boolean member as a parameter :
private boolean tryLoginActivity(AuthorizationRequest request) {
Intent intent = getLoginActivityIntent(request);
if (!resolveIntent(intent)) {
return false;
}
try {
request.getStartActivityDelegate().startActivityForResult(intent, request.getRequestCode(),this.insideTabGroup);
} catch (ActivityNotFoundException e) {
return false;
}
return true;
}
3 Set the boolean member in the session :
Session session = Session.getActiveSession();
session.insideTabGroup = true;
That should do the trick.
Cdt
I had this same error with the Parse.com Facebook SDK integration and was down to me missing the call to ParseFacebookUtils.finishAuthentication which is noted in the docs.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
ParseFacebookUtils.finishAuthentication(requestCode, resultCode, data);
}