Skip to content

Instantly share code, notes, and snippets.

@ianbarber
Last active December 29, 2023 03:42
Show Gist options
  • Star 57 You must be signed in to star a gist
  • Fork 28 You must be signed in to fork a gist
  • Save ianbarber/5170508 to your computer and use it in GitHub Desktop.
Save ianbarber/5170508 to your computer and use it in GitHub Desktop.
Example Sign In activity for Google Sign-In on Android that retrieves an authorization code for use with server side authentication. See http://www.riskcompletefailure.com/2016/07/server-side-google-api-access-from.html for more background and links.
package com.example.anothersignintest;
import com.google.android.gms.auth.api.Auth;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.auth.api.signin.GoogleSignInResult;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.OptionalPendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
public class SignInTestActivity extends AppCompatActivity implements
GoogleApiClient.OnConnectionFailedListener, OnClickListener {
private static final String TAG = "SignInTestActivity";
// A magic number we will use to know that our sign-in error
// resolution activity has completed.
private static final int OUR_REQUEST_CODE = 49404;
// The core Google Play Services client.
private GoogleApiClient mGoogleApiClient;
// A progress dialog to display when the user is connecting in
// case there is a delay in any of the dialogs being ready.
private ProgressDialog mConnectionProgressDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sign_in_test);
// First we need to configure the Google Sign In API to ensure we are retrieving
// the server authentication code as well as authenticating the client locally.
String serverClientId = getString(R.string.server_client_id);
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestServerAuthCode(serverClientId)
.requestEmail()
.build();
// We pass through three "this" arguments to the builder, specifying the:
// 1. Context
// 2. Object to use for resolving connection errors
// 3. Object to call onConnectionFailed on
// We also add the Google Sign in API we previously created.
mGoogleApiClient = new GoogleApiClient.Builder(this /* Context */)
.enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
// Connect our sign in, sign out and disconnect buttons.
findViewById(R.id.sign_in_button).setOnClickListener(this);
findViewById(R.id.sign_out_button).setOnClickListener(this);
findViewById(R.id.revoke_access_button).setOnClickListener(this);
findViewById(R.id.sign_out_button).setVisibility(View.INVISIBLE);
findViewById(R.id.revoke_access_button).setVisibility(View.INVISIBLE);
// Configure the ProgressDialog that will be shown if there is a
// delay in presenting the user with the next sign in step.
mConnectionProgressDialog = new ProgressDialog(this);
mConnectionProgressDialog.setMessage("Signing in...");
}
@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. We can try and retrieve an
// authentication code.
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.
final ProgressDialog progressDialog = new ProgressDialog(this);
progressDialog.setMessage("Checking sign in state...");
progressDialog.show();
opr.setResultCallback(new ResultCallback<GoogleSignInResult>() {
@Override
public void onResult(@NonNull GoogleSignInResult googleSignInResult) {
progressDialog.dismiss();
handleSignInResult(googleSignInResult);
}
});
}
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
// When we get here in an automanager activity the error is likely not
// resolvable - meaning Google Sign In and other Google APIs will be
// unavailable.
Log.d(TAG, "onConnectionFailed:" + connectionResult);
}
protected void onActivityResult(int requestCode, int responseCode,
Intent intent) {
super.onActivityResult(requestCode, responseCode, intent);
Log.v(TAG, "ActivityResult: " + requestCode);
if (requestCode == OUR_REQUEST_CODE) {
// Hide the progress dialog if its showing.
mConnectionProgressDialog.dismiss();
// Resolve the intent into a GoogleSignInResult we can process.
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(intent);
handleSignInResult(result);
}
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.sign_in_button:
Log.v(TAG, "Tapped sign in");
// Show the dialog as we are now signing in.
mConnectionProgressDialog.show();
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, OUR_REQUEST_CODE);
break;
case R.id.sign_out_button:
Log.v(TAG, "Tapped sign out");
// This will clear the default account in order to allow the user
// to potentially choose a different account from the
// account chooser.
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
@Override
public void onResult(@NonNull Status status) {
// Hide the sign out buttons, show the sign in button.
findViewById(R.id.sign_in_button).setVisibility(View.VISIBLE);
findViewById(R.id.sign_out_button)
.setVisibility(View.INVISIBLE);
findViewById(R.id.revoke_access_button).setVisibility(
View.INVISIBLE);
}
});
break;
case R.id.revoke_access_button:
Log.v(TAG, "Tapped disconnect");
// Go away and revoke access to this entire application.
Auth.GoogleSignInApi.revokeAccess(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
@Override
public void onResult(@NonNull Status status) {
// The GoogleApiClient is now disconnected and access has been
// revoked. We should now delete any data we need to comply with
// the developer properties.
// Hide the sign out buttons, show the sign in button.
findViewById(R.id.sign_in_button).setVisibility(View.VISIBLE);
findViewById(R.id.sign_out_button).setVisibility(View.INVISIBLE);
findViewById(R.id.revoke_access_button).setVisibility(View.INVISIBLE);
}
});
break;
default:
// Unknown id.
Log.v(TAG, "Unknown button press");
}
}
/**
* Helper method to trigger retrieving the server auth code if we've signed in.
*/
private void handleSignInResult(GoogleSignInResult result ) {
if (result.isSuccess()) {
GoogleSignInAccount acct = result.getSignInAccount();
// If you don't already have a server session, you can now send this code to your
// server to authenticate on the backend.
String authCode = acct.getServerAuthCode();
// Hide the sign in buttons, show the sign out button.
findViewById(R.id.sign_in_button).setVisibility(View.INVISIBLE);
findViewById(R.id.sign_out_button)
.setVisibility(View.VISIBLE);
findViewById(R.id.revoke_access_button).setVisibility(
View.VISIBLE);
}
}
}
@ahaan
Copy link

ahaan commented Jul 31, 2013

hey Ian
i am trying to use your example for my app.
when i run the app i got this type or error " error opening trace file: No such file or directory (2)"
plz help me

@jatinpanwar55
Copy link

Awesome example

Copy link

ghost commented Nov 6, 2014

On first signup how do you handle repeated UserRecoverableAuthException

@richasonisoni
Copy link

Hi , Mr kalidas the website holder of github, am unable to see the complete code as like before , ex- src folder, main activity , manifest file an all folders separately . have this site has done any modifications , even i hv to make an account for this site ., but earlier it was not so , it was easy to access it , now pls help me for receiving codes or accesing this site.

@richasonisoni
Copy link

please reply on my email richason023@gmail.com

@tejaslodaya
Copy link

I want to navigate from LoginScreen activity to the MainActivity once its done. Can you assist me on how its done. Comments in the above code came in handy!
Cheers! @ianbarbe

@Souch007
Copy link

Souch007 commented Aug 8, 2016

WANT TO LOGOUT FROM OTHER ACTIVITY i.e from Navigation Drawer ,
mGoogleApiClient is null always

@prat3ik
Copy link

prat3ik commented Jan 27, 2018

Hi @ianbarber, I have other activity who do Sign Out, so How to do that? Means I have to pass mGoogleApiClient object to other activity, can you please suggest me the best way to do that ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment