Lenny
Lenny

Reputation: 917

Facebook and Google authentication within Android app

I am trying to integrate Facebook and Google authentication for my mobile application. I have followed Google and Facebook tutorials on how to do it and both projects work fine when they are separated. In my current solution signing in with Google works ok but Facebook gives me following error msg:

Permission Denial: get/set setting for user asks to run as user -2 but is calling from user 0; this requires android.permission.INTERACT_ACROSS_USERS_FULL

E/Parcel: Class not found when unmarshalling: com.facebook.login.LoginClient$Request

Caused by: java.lang.NoClassDefFoundError: com/facebook/login/LoginClient$Request

Caused by: java.lang.ClassNotFoundException: Didn't find class "com.facebook.login.LoginClient$Request" on path

Here is my LoginAvtivity class I use for authentication:

public class ActivityLogin extends AppCompatActivity implements GoogleApiClient.OnConnectionFailedListener, View.OnClickListener {

private static final String TAG = "SignInActivity";
private static final int RC_SIGN_IN = 9001;

private GoogleApiClient mGoogleApiClient;
private ProgressDialog mProgressDialog;

private LoginButton facebookButton;
private CallbackManager facebookCallbackManager;

@Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    FacebookSdk.sdkInitialize(getApplicationContext());
    facebookCallbackManager = CallbackManager.Factory.create();
    setContentView(R.layout.activity_login);




    // Button listeners
    findViewById(R.id.google_button).setOnClickListener(this);
    facebookButton = (LoginButton)findViewById(R.id.facebook_button);

    // [START configure_signin]
    // Configure sign-in to request the user's ID, email address, and basic
    // profile. ID and basic profile are included in DEFAULT_SIGN_IN.
    GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestEmail()
            .requestIdToken(getString(R.string.server_client_id))
            .build();

    // [START build_client]
    // Build a GoogleApiClient with access to the Google Sign-In API and the
    // options specified by gso.
    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
            .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
            .build();

    // [START customize_button]
    // Customize sign-in button. The sign-in button can be displayed in
    // multiple sizes and color schemes. It can also be contextually
    // rendered based on the requested scopes. For example. a red button may
    // be displayed when Google+ scopes are requested, but a white button
    // may be displayed when only basic profile is requested. Try adding the
    // Scopes.PLUS_LOGIN scope to the GoogleSignInOptions to see the
    // difference.
    SignInButton signInButton = (SignInButton) findViewById(R.id.google_button);
    signInButton.setSize(SignInButton.SIZE_STANDARD);
    signInButton.setScopes(gso.getScopeArray());

    setGooglePlusButtonText(signInButton, "Sign in with Google");

    facebookButton.registerCallback(facebookCallbackManager, new FacebookCallback<LoginResult>() {
        @Override
        public void onSuccess(LoginResult loginResult) {
            Intent intent = new Intent(ActivityLogin.this, MainActivity.class);
            startActivity(intent);
        }

        @Override
        public void onCancel() {
            Log.d("TOKEN", "Canceled!!!!!!!!!!");

        }

        @Override
        public void onError(FacebookException error) {
            Log.d("TOKEN", "CHUUUUUUJ WIELKI!!!!!!!!!!!!");

        }
    });
}

@Override
public void onStart() {
    super.onStart();

    OptionalPendingResult<GoogleSignInResult> opr = Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient);
    if (opr.isDone()) {
        // If the user's cached credentials are valid, the OptionalPendingResult will be "done"
        // and the GoogleSignInResult will be available instantly.
        Log.d(TAG, "Got cached sign-in");
        GoogleSignInResult result = opr.get();
        handleSignInResult(result);
    } else {
        // If the user has not previously signed in on this device or the sign-in has expired,
        // this asynchronous branch will attempt to sign in the user silently.  Cross-device
        // single sign-on will occur in this branch.
        showProgressDialog();
        opr.setResultCallback(new ResultCallback<GoogleSignInResult>() {
            @Override
            public void onResult(GoogleSignInResult googleSignInResult) {
                hideProgressDialog();
                handleSignInResult(googleSignInResult);
            }
        });
    }
}

// [START onActivityResult]
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
    if (requestCode == RC_SIGN_IN) {
        GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
        handleSignInResult(result);
    }
}
// [END onActivityResult]

// [START handleSignInResult]
private void handleSignInResult(GoogleSignInResult result) {
    Log.d(TAG, "handleSignInResult:" + result.isSuccess());
    if (result.isSuccess()) {
        // Signed in successfully, show authenticated UI.
        GoogleSignInAccount acct = result.getSignInAccount();
        //mStatusTextView.setText(getString(R.string.signed_in_fmt, acct.getDisplayName()));
        //updateUI(true);
        Intent intent = new Intent(ActivityLogin.this, MainActivity.class);
        startActivity(intent);

        String idToken = acct.getIdToken();
        if (idToken != null) {
            Log.d("TOKEN", idToken);
            //sendEmail(idToken);
        } else {
            Log.d("TOKEN", "CHUUUUUUJ WIELKI!");
        }
    } else {
        // Signed out, show unauthenticated UI.
        //updateUI(false);
    }
}
// [END handleSignInResult]

// [START signIn]
private void signIn() {
    Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
    startActivityForResult(signInIntent, RC_SIGN_IN);
}
// [END signIn]



@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
    // An unresolvable error has occurred and Google APIs (including Sign-In) will not
    // be available.
    Log.d(TAG, "onConnectionFailed:" + connectionResult);
}

private void showProgressDialog() {
    if (mProgressDialog == null) {
        mProgressDialog = new ProgressDialog(this);
        mProgressDialog.setMessage(getString(R.string.loading));
        mProgressDialog.setIndeterminate(true);
    }

    mProgressDialog.show();
}

private void hideProgressDialog() {
    if (mProgressDialog != null && mProgressDialog.isShowing()) {
        mProgressDialog.hide();
    }
}

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.google_button:
            signIn();
            break;
        case R.id.tutorial:
            Intent intent = new Intent(this, TutorialActivity.class);
            startActivity(intent);
            break;
//            case R.id.disconnect_button:
//                revokeAccess();
//                break;
    }
}

protected void setGooglePlusButtonText(SignInButton signInButton, String buttonText) {
    // Find the TextView that is inside of the SignInButton and set its text
    for (int i = 0; i < signInButton.getChildCount(); i++) {
        View v = signInButton.getChildAt(i);

        if (v instanceof TextView) {
            TextView tv = (TextView) v;
            tv.setText(buttonText);
            return;
        }
    }
  }
}                        

And here is the xml layout for this class:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".ActivityLogin"
android:background="@drawable/background_gradient">

<com.facebook.login.widget.LoginButton
    android:id="@+id/facebook_button"
    android:layout_width="200dp"
    android:layout_height="40dp"
    android:layout_above="@+id/google_button"
    android:layout_centerHorizontal="true"
    android:layout_marginBottom="20dp" />

<com.google.android.gms.common.SignInButton
    android:id="@+id/google_button"
    android:layout_width="200dp"
    android:layout_height="40dp"
    android:layout_alignParentBottom="true"
    android:layout_centerHorizontal="true"
    android:layout_marginBottom="60dp"
    />

It seems that I am missing something imporant here but I cannot find what it is. The first error message says that I am missing permissions but according to both google and facebook tutorials this particular permission is not required.

Upvotes: 0

Views: 550

Answers (1)

Jyotman Singh
Jyotman Singh

Reputation: 11330

You are not handling the Facebook result in your onActivityResult() method.

Add this to your method -

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

    // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
    if (requestCode == RC_SIGN_IN) {
        GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
        handleSignInResult(result);
    } 
    else{
        //Add this to handle Facebook result
        facebookCallbackManager.onActivityResult(requestCode, resultCode, data);
    }
}

Upvotes: 1

Related Questions