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.
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);
}
}
Related
I'm trying to authenticate with backend server from mobile app.
I was following this documentation. https://developers.google.com/identity/sign-in/android/sign-in
However, there are some errors. RC_SIGN_IN and updateUI() cannot be resolved.
My code is like this
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
...
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.build();
mGoogleSignInClient = GoogleSignIn.getClient(this, gso);
mSignInButton = findViewById(R.id.sign_in_button);
mSignInButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, "Hello", Toast.LENGTH_LONG).show();
Intent signIntent = mGoogleSignInClient.getSignInIntent();
startActivityForResult(signIntent, RC_SIGN_IN);
}
});
#Override
protected void onStart() {
GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this);
updateUI(account);
super.onStart();
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Result returned from launching the Intent from GoogleSignInClient.getSignInIntent(...);
if (requestCode == RC_SIGN_IN) {
// The Task returned from this call is always completed, no need to attach
// a listener.
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
handleSignInResult(task);
}
}
private void handleSignInResult(Task<GoogleSignInAccount> completedTask) {
try {
GoogleSignInAccount account = completedTask.getResult(ApiException.class);
String idToken = account.getIdToken();
// Send Id Token to the backend and validate here
// Signed in successfully, show authenticated UI.
updateUI(account);
} catch (ApiException e) {
// The ApiException status code indicates the detailed failure reason.
// Please refer to the GoogleSignInStatusCodes class reference for more information.
Log.w(TAG, "signInResult:failed code=" + e.getStatusCode());
updateUI(null);
}
}
Update
Now the button itself doesn't work.
xml
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<!-- Include the main content -->
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.gms.common.SignInButton
android:id="#+id/sign_in_button"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/text_view_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.v4.widget.NestedScrollView>
</FrameLayout>
<!-- Navigation bar -->
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:menu="#menu/navigation_menu"/>
</android.support.v4.widget.DrawerLayout>
How can I fix this?
You need to do nothing but replace RC_SIGN_IN with an int value. It can be anything but use 1 as it's value. Do as follows:
startActivityForResult(signIntent, 1);
And change the if code in activity result as follows:
if (requestCode == 1)
Also change the sign in button click code to this(remove switch cases):
mSignInButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
signIn();
}
}
});
This is because you are calling on click method to the button and then again checking If the same button is clicked, that's why I think it's not working.
Now for the updateUI method, this method should be defined by you. Basically, this is for your app to change what is shown to the user when he/she has signed into the app. If you want to open new activity when signedIn() you can use Intent by changing the updateUI(account) in the activity result and onstart event to an intent:
startActivity(new Intent(MainActivity.this, SecondActivity.class));
And get which account is signedin in the SecondActivity:
GoogleSignInAccount account = GoogleSignIn.g etLastSignedInAccount(this); //use this in onCreate
Try this one.
In MainActivity, implement View.OnClickListener and GoogleApiClient.OnConnectionFailedListener
private static final String TAG = MainActivity.class.getSimpleName();
private static final int RC_SIGN_IN = 007;
private GoogleApiClient mGoogleApiClient;
GoogleSignInOptions gso = new
GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.build();
GoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this, this)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
btnSignIn.setSize(SignInButton.SIZE_STANDARD);
btnSignIn.setScopes(gso.getScopeArray());
private void handleSignInResult(GoogleSignInResult result) {
Log.d(TAG, "handleSignInResult:" + result.isSuccess());
if (result.isSuccess()) {
// Signed in successfully, show authenticated UI.
GoogleSignInAccount acct = result.getSignInAccount();
Log.e(TAG, "display name: " + acct.getDisplayName());
String personName = acct.getDisplayName();
String personPhotoUrl = acct.getPhotoUrl().toString();
String email = acct.getEmail();
Log.e(TAG, "Name: " + personName + ", email: " + email
+ ", Image: " + personPhotoUrl);
txtName.setText(personName);
txtEmail.setText(email);
Glide.with(getApplicationContext()).load(personPhotoUrl)
.thumbnail(0.5f)
.into(imgProfilePic);
updateUI(true);
} else {
// Signed out, show unauthenticated UI.
updateUI(false);
}
}
private void signIn() {
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, RC_SIGN_IN);
}
private void signOut() {
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
updateUI(false);
}
});
}
private void revokeAccess() {
Auth.GoogleSignInApi.revokeAccess(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
updateUI(false);
}
});
}
#Override
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.btn_sign_in:
signIn();
break;
case R.id.btn_sign_out:
signOut();
break;
case R.id.btn_revoke_access:
revokeAccess();
break;
}
}
#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);
}
}
#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);
}
});
}
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.d(TAG, "onConnectionFailed:" + connectionResult);
}
private void updateUI(boolean isSignedIn) {
if (isSignedIn) {
btnSignIn.setVisibility(View.GONE);
btnSignOut.setVisibility(View.VISIBLE);
btnRevokeAccess.setVisibility(View.GONE);
llProfileLayout.setVisibility(View.VISIBLE);
} else {
btnSignIn.setVisibility(View.VISIBLE);
btnSignOut.setVisibility(View.GONE);
btnRevokeAccess.setVisibility(View.GONE);
llProfileLayout.setVisibility(View.GONE);
}
}
RC_SIGN_IN is basically an int number code that is used to identify that your onActivityResult is called for google sign-in.
private static final int RC_SIGN_IN = 007;
updateUi() is method used to let user know that google Signin is successfull or not. Here is method:
private void updateUI(GoogleSignInAccount signedIn) {
if (signedIn != null) {
// sigin is successfull
signInButton.setVisibility(View.GONE);
signOutButton.setVisibility(View.VISIBLE);
} else {
// sigin is cancelled
signInButton.setVisibility(View.VISIBLE);
signOutButton.setVisibility(View.GONE);
}
}
I have used Google sign-in feature in my android app. I have used their standard code for login and have tested it by deploying it on my mobile device in debug mode. Everything works fine this way.
I have now moved my app to Google Play Store for closed beta testing. When I install my app from Play Store it fails at the login step as I noticed it returns null for user's email, id and displayName fields. I have no idea what is going wrong after installing it from Play Store.
The sign-in code is given below:
private static final int RC_SIGN_IN = 9001;
private GoogleApiClient mGoogleApiClient;
private GoogleSignInAccount acct;
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.build();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
SignInButton signInButton = (SignInButton) findViewById(R.id.sign_in_button);
signInButton.setSize(SignInButton.SIZE_STANDARD);
signInButton.setScopes(gso.getScopeArray());
#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.
isFirstLogin = false;
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.
isFirstLogin = true;
showProgressDialog();
opr.setResultCallback(new ResultCallback<GoogleSignInResult>() {
#Override
public void onResult(GoogleSignInResult googleSignInResult) {
hideProgressDialog();
handleSignInResult(googleSignInResult);
}
});
}
}
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) {
if (result.isSuccess()) {
// Signed in successfully, show authenticated UI.
acct = result.getSignInAccount();
mStatusTextView.setText(getString(R.string.signed_in_fmt, acct.getDisplayName()));
updateUI(true);
final AsyncTask<Integer, Void, HelloUserResponse> addUser =
new AsyncTask<Integer, Void, HelloUserResponse>()
{
#Override
protected HelloUserResponse doInBackground(Integer... integers) {
// Retrieve service handle.
Helloworld apiServiceHandle = AppConstants.getApiServiceHandle();
try {
HelloUser heUser = new HelloUser();
heUser.setUseremail(acct.getEmail());
heUser.setUserid(acct.getId());
heUser.setUsername(acct.getDisplayName());
Helloworld.Greetings.AddUser addUserCommand = apiServiceHandle.greetings().addUser(heUser);
HelloUserResponse helloUserRsp = addUserCommand.execute();
return helloUserRsp;
} catch (IOException e) {
Toast.makeText(SignInActivity.this, "Something went wrong",
Toast.LENGTH_SHORT).show();
}
return null;
}
#Override
protected void onPostExecute(HelloUserResponse helloUserRsp) {
if(helloUserRsp.getResult()!=0L)
{
Intent myIntent = new Intent(getApplicationContext(), MainActivity.class);
SharedPreferences myprefs = getApplicationContext().getSharedPreferences("user", MODE_WORLD_READABLE);
myprefs.edit().putString("user_name", acct.getDisplayName()).commit();
myprefs.edit().putString("user_email", acct.getEmail()).commit();
myprefs.edit().putLong("user_id", helloUserRsp.getResult()).commit();
startActivity(myIntent);
}
else {
updateUI(false);
}
}
};
if(isFirstLogin)
addUser.execute(0);
else
{
Intent myIntent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(myIntent);
}
}
else {
// Signed out, show unauthenticated UI.
updateUI(false);
}
}
Google Login couldn't get Response in Lollipop
Hi i need to integrate google login in my app.
I found help from https://developers.google.com and get code from https://github.com/googlesamples/google-services/tree/master/android/signin.
I tested it within 4.1, 4.4 as well.
It works fine in all versions but not worked in Lollipop.
Whenever i run in lollipop then it shows progress dialog and then also gets a/c of google but then can not get any response.
Google Login Code
public class SignInActivity 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 TextView mStatusTextView;
private ProgressDialog mProgressDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Views
mStatusTextView = (TextView) findViewById(R.id.status);
// Button listeners
findViewById(R.id.sign_in_button).setOnClickListener(this);
findViewById(R.id.sign_out_button).setOnClickListener(this);
findViewById(R.id.disconnect_button).setOnClickListener(this);
// [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()
.build();
// [END configure_signin]
// [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();
// [END build_client]
// [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.sign_in_button);
signInButton.setSize(SignInButton.SIZE_STANDARD);
signInButton.setScopes(gso.getScopeArray());
// [END customize_button]
}
#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);
} 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]
// [START signOut]
private void signOut() {
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
// [START_EXCLUDE]
updateUI(false);
// [END_EXCLUDE]
}
});
}
// [END signOut]
// [START revokeAccess]
private void revokeAccess() {
Auth.GoogleSignInApi.revokeAccess(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
// [START_EXCLUDE]
updateUI(false);
// [END_EXCLUDE]
}
});
}
// [END revokeAccess]
#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();
}
}
private void updateUI(boolean signedIn) {
if (signedIn) {
findViewById(R.id.sign_in_button).setVisibility(View.GONE);
findViewById(R.id.sign_out_and_disconnect).setVisibility(View.VISIBLE);
} else {
mStatusTextView.setText(R.string.signed_out);
findViewById(R.id.sign_in_button).setVisibility(View.VISIBLE);
findViewById(R.id.sign_out_and_disconnect).setVisibility(View.GONE);
}
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.sign_in_button:
signIn();
break;
case R.id.sign_out_button:
signOut();
break;
case R.id.disconnect_button:
revokeAccess();
break;
}
}
}
I tried the google developer documentation and tried sign-in for my app.
The code is copied from the git with added codes from the documentation.
and defined in LoginActivity as
Public class LoginActivity extends AppCompatActivity implements
GoogleApiClient.OnConnectionFailedListener,
View.OnClickListener {
private static final String TAG = "* * SignIn * *";
private static final int RC_SIGN_IN = 9001;
private GoogleApiClient mGoogleApiClient;
private ProgressDialog mProgressDialog;
Bundle userData = new Bundle();
Intent newIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
findViewById(R.id.sign_in_button).setOnClickListener(this);
// [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()
.build();
// [END configure_signin]
// [START build_client]
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
// [END build_client]
// [START customize_button]
SignInButton signInButton = (SignInButton) findViewById(R.id.sign_in_button);
signInButton.setSize(SignInButton.SIZE_STANDARD);
signInButton.setScopes(gso.getScopeArray());
// [END customize_button]
}
#Override
public void onStart() {
super.onStart();
OptionalPendingResult<GoogleSignInResult> opr = Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient);
if (opr.isDone()) {
Log.d(TAG, "Got cached sign-in");
GoogleSignInResult result = opr.get();
handleSignInResult(result);
} else {
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();
userData.putString("Username", acct.getDisplayName());
userData.putString("Email",acct.getEmail());
newIntent = new Intent(LoginActivity.this, MainActivity.class);
newIntent.putExtras(userData);
startActivity(newIntent);
finish();
} else {
userData.putString("Username", "Anonymous");
userData.putString("Email","www.example.com");
newIntent = new Intent(LoginActivity.this, MainActivity.class);
newIntent.putExtras(userData);
startActivity(newIntent);
finish();
}
}
// [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) {
Log.d(TAG, "onConnectionFailed:" + connectionResult);
}
private void showProgressDialog() {
if (mProgressDialog == null) {
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setMessage("Please wait");
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.sign_in_button:
signIn();
break;
}
}
}
But I get following error log.
as
12-16 23:02:44.074 5545-5545/com.example.www.newapp E/AndroidRuntime: java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=40962, result=-1, data=Intent { (has extras) }}
to activity {com.example.www.newapp/com.google.android.gms.auth.api.signin.internal.SignInHubActivity}:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Class java.lang.Object.getClass()' on a null object reference
My MainActivity code is as
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener, View.OnClickListener {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
View header = navigationView.getHeaderView(0);
userName = (TextView) header.findViewById(R.id.userName);
userName.setText(user);//Username recieved through intent
}}
While running it in emulator it shows update your play service, is it a problem?
The Error occurred only in emulator in when compiling with new play service 8.3
While testing in actual hardware doesn't show any problem. It is due to the mismatch in the play service versions in emulator and the API.
Hope they upgrade the Google API SDK with latest play service and release some notice about it.
I met a problem in my project.
I want to use "Google API" to log in in my LoginActivity. And Log out from another Activity(named WelcomeActivity)
LoginActivity:
(code is here)
public class LoginActivity extends AppCompatActivity implements
GoogleApiClient.OnConnectionFailedListener,
View.OnClickListener {
// Configuration of Google API - Step 1/3
private static final String TAG = "LoginActivity";
private static final int RC_SIGN_IN = 9001;
public static GoogleApiClient mGoogleApiClient;
private ProgressDialog mProgressDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GoogleAPI();
}
public void GoogleAPI(){
// Button listeners
findViewById(R.id.sign_in_button).setOnClickListener(this);
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.build();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
}
#Override
public void onStart() {
super.onStart();
....
}
// [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) {
if (result.isSuccess()) {
// Signed in successfully, show authenticated UI.
CustomApplication app = (CustomApplication)getApplication();
GoogleSignInAccount acct = result.getSignInAccount();
Intent i = new Intent(LoginActivity.this, WelcomePage.class);
i.putExtra("Username", acct.getDisplayName());
startActivity(i);
}
}
// [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) {
...
}
private void showProgressDialog() {
...
}
private void hideProgressDialog() {
...
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.sign_in_button:
signIn();
break;
….
}
}
}
And I want to use Sign_out Method in my Welcome activity,
private void signOut() {
// Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
// new ResultCallback<Status>() {
// #Override
// public void onResult(Status status) {
// // [START_EXCLUDE]
//// updateUI(false);
// // [END_EXCLUDE]
// }
// });
// }
In order to solve this problem, i try 2 methods:
make mGoogleApiClient as a global variable(extends Application or Singleton), i try it, but failed, in Welcome page, mGoogleApiClient is not null, but error is: mGoogleApiClient is not connected yet.
i call LoginActivity.getMGoogleApiClient(static variable), but also failed, same error: mGoogleApiClient is not connected yet.
I already search this problem for days, but nothing useful to solve it, please help me ..
When you enableAutoManage, then the googleApiClient gets connected onStart and gets disconnected onStop and is handled automatically by the library. What you could is, logout the user in the other activity, whatever your code is to logout the user from your backend, except don't sign out from google yet.
Pseudo code:
private void logOut(){
//your logout code in the log out activity
setCurrentUser(null);
}
And in the activity with the googleApiClient, you could check if the user is logged-in in onConnected callback of googleApiClient. If the current user is not logged in, sign out the user from Google.
#Override
public void onConnected(Bundle connectionHint) {
if (getCurrentUser() == null){
signOut();
}
}
private void signOut() {
Auth.GoogleSignInApi.signOut(mGoogleApiClientPlus).setResultCallback(
new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
//signed out.
}
});
}
If you don't use enableAutoManage and don't disconnect the client in onStop (which I don't know if it's recommended), you could use your 2 methods but I won't recommend using static fields for googleApiClient object.
One solution is to do your normal logout flow (ignore mGoogleApiClient). The next time the user opens your app to the login screen and hits google login, you log them out first, then do the google login
e.g.:
private void googleLogin() {
googleLogout();
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, RC_SIGN_IN);
}
private void googleLogout() {
if (mGoogleApiClient.isConnected()) {
Auth.GoogleSignInApi.signOut(mGoogleApiClient);
}
}