Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion auth/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ dependencies {
implementation("com.google.firebase:firebase-auth")

// Google Identity Services SDK (only required for Auth with Google)
implementation("com.google.android.gms:play-services-auth:21.2.0")
implementation("androidx.credentials:credentials:1.3.0")
implementation("androidx.credentials:credentials-play-services-auth:1.3.0")
implementation("com.google.android.libraries.identity.googleid:googleid:1.1.1")

// Firebase UI
// Used in FirebaseUIActivity.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,41 +16,36 @@

package com.google.firebase.quickstart.auth.java;

import android.app.PendingIntent;
import android.content.Intent;
import static com.google.android.libraries.identity.googleid.GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL;

import android.os.Bundle;
import android.os.CancellationSignal;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.IntentSenderRequest;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.google.android.gms.auth.api.identity.BeginSignInRequest;
import com.google.android.gms.auth.api.identity.BeginSignInResult;
import com.google.android.gms.auth.api.identity.GetSignInIntentRequest;
import com.google.android.gms.auth.api.identity.Identity;
import com.google.android.gms.auth.api.identity.SignInClient;
import com.google.android.gms.auth.api.identity.SignInCredential;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import androidx.credentials.ClearCredentialStateRequest;
import androidx.credentials.Credential;
import androidx.credentials.CredentialManager;
import androidx.credentials.CredentialManagerCallback;
import androidx.credentials.CustomCredential;
import androidx.credentials.GetCredentialRequest;
import androidx.credentials.GetCredentialResponse;
import androidx.credentials.exceptions.ClearCredentialException;
import androidx.credentials.exceptions.GetCredentialException;
import com.google.android.libraries.identity.googleid.GetGoogleIdOption;
import com.google.android.libraries.identity.googleid.GetSignInWithGoogleOption;
import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential;
import com.google.android.material.snackbar.Snackbar;
import com.google.firebase.auth.AuthCredential;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.auth.GoogleAuthProvider;
import com.google.firebase.quickstart.auth.R;
import com.google.firebase.quickstart.auth.databinding.FragmentGoogleBinding;
import java.util.concurrent.Executors;

/**
* Demonstrate Firebase Authentication using a Google ID Token.
Expand All @@ -61,19 +56,9 @@ public class GoogleSignInFragment extends BaseFragment {

private FirebaseAuth mAuth;

private SignInClient signInClient;
private CredentialManager credentialManager;
private FragmentGoogleBinding mBinding;

private final ActivityResultLauncher<IntentSenderRequest> signInLauncher = registerForActivityResult(
new ActivityResultContracts.StartIntentSenderForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
handleSignInResult(result.getData());
}
}
);

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Expand All @@ -86,30 +71,19 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
super.onViewCreated(view, savedInstanceState);
setProgressBar(mBinding.progressBar);

// Button listeners
mBinding.signInButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
signIn();
}
});
mBinding.signOutButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
signOut();
}
});

// Configure Google Sign In
signInClient = Identity.getSignInClient(requireContext());
// Initialize Credential Manager
credentialManager = CredentialManager.create(requireContext());

// Initialize Firebase Auth
mAuth = FirebaseAuth.getInstance();

// Display One-Tap Sign In if user isn't logged in
FirebaseUser currentUser = mAuth.getCurrentUser();
if (currentUser == null) {
oneTapSignIn();
// Button listeners
mBinding.signInButton.setOnClickListener(v -> signIn());
mBinding.signOutButton.setOnClickListener(v -> signOut());

// Display Credential Manager Bottom Sheet if user isn't logged in
if (mAuth.getCurrentUser() == null) {
showBottomSheet();
}
}

Expand All @@ -121,132 +95,135 @@ public void onStart() {
updateUI(currentUser);
}

private void handleSignInResult(Intent data) {
try {
// Google Sign In was successful, authenticate with Firebase
SignInCredential credential = signInClient.getSignInCredentialFromIntent(data);
String idToken = credential.getGoogleIdToken();
Log.d(TAG, "firebaseAuthWithGoogle:" + credential.getId());
firebaseAuthWithGoogle(idToken);
} catch (ApiException e) {
// Google Sign In failed, update UI appropriately
Log.w(TAG, "Google sign in failed", e);
updateUI(null);
}
}

private void firebaseAuthWithGoogle(String idToken) {
showProgressBar();
AuthCredential credential = GoogleAuthProvider.getCredential(idToken, null);
mAuth.signInWithCredential(credential)
.addOnCompleteListener(requireActivity(), new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success");
FirebaseUser user = mAuth.getCurrentUser();
updateUI(user);
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCredential:failure", task.getException());
Snackbar.make(mBinding.mainLayout, "Authentication Failed.", Snackbar.LENGTH_SHORT).show();
updateUI(null);
}

hideProgressBar();
}
});
}

private void signIn() {
GetSignInIntentRequest signInRequest = GetSignInIntentRequest.builder()
.setServerClientId(getString(R.string.default_web_client_id))
// Create the dialog configuration for the Credential Manager request
GetSignInWithGoogleOption signInWithGoogleOption = new GetSignInWithGoogleOption
.Builder(requireContext().getString(R.string.default_web_client_id))
.build();

signInClient.getSignInIntent(signInRequest)
.addOnSuccessListener(new OnSuccessListener<PendingIntent>() {
@Override
public void onSuccess(PendingIntent pendingIntent) {
launchSignIn(pendingIntent);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Log.e(TAG, "Google Sign-in failed", e);
}
});
// Create the Credential Manager request using the configuration created above
GetCredentialRequest request = new GetCredentialRequest.Builder()
.addCredentialOption(signInWithGoogleOption)
.build();

launchCredentialManager(request);
}

private void oneTapSignIn() {
// Configure One Tap UI
BeginSignInRequest oneTapRequest = BeginSignInRequest.builder()
.setGoogleIdTokenRequestOptions(
BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
.setSupported(true)
.setServerClientId(getString(R.string.default_web_client_id))
.setFilterByAuthorizedAccounts(true)
.build()
)
private void showBottomSheet() {
// Create the bottom sheet configuration for the Credential Manager request
GetGoogleIdOption googleIdOption = new GetGoogleIdOption.Builder()
.setFilterByAuthorizedAccounts(true)
.setServerClientId(requireContext().getString(R.string.default_web_client_id))
.build();

// Create the Credential Manager request using the configuration created above
GetCredentialRequest request = new GetCredentialRequest.Builder()
.addCredentialOption(googleIdOption)
.build();

// Display the One Tap UI
signInClient.beginSignIn(oneTapRequest)
.addOnSuccessListener(new OnSuccessListener<BeginSignInResult>() {
launchCredentialManager(request);
}

private void launchCredentialManager(GetCredentialRequest request) {
credentialManager.getCredentialAsync(
requireContext(),
request,
new CancellationSignal(),
Executors.newSingleThreadExecutor(),
new CredentialManagerCallback<>() {
@Override
public void onSuccess(BeginSignInResult beginSignInResult) {
launchSignIn(beginSignInResult.getPendingIntent());
public void onResult(GetCredentialResponse result) {
// Extract credential from the result returned by Credential Manager
createGoogleIdToken(result.getCredential());
}
})
.addOnFailureListener(new OnFailureListener() {

@Override
public void onFailure(@NonNull Exception e) {
// No saved credentials found. Launch the One Tap sign-up flow, or
// do nothing and continue presenting the signed-out UI.
public void onError(GetCredentialException e) {
Log.e(TAG, "Couldn't retrieve user's credentials: " + e.getLocalizedMessage());
}
});
}
);
}

private void launchSignIn(PendingIntent pendingIntent) {
try {
IntentSenderRequest intentSenderRequest = new IntentSenderRequest.Builder(pendingIntent)
.build();
signInLauncher.launch(intentSenderRequest);
} catch (Exception e) {
Log.e(TAG, "Couldn't start Sign In: " + e.getLocalizedMessage());
private void createGoogleIdToken(Credential credential) {
// Update UI to show progress bar while response is being processed
requireActivity().runOnUiThread(this::showProgressBar);

// Check if credential is of type Google ID
if (credential instanceof CustomCredential customCredential
&& credential.getType().equals(TYPE_GOOGLE_ID_TOKEN_CREDENTIAL)) {
// Create Google ID Token
Bundle credentialData = customCredential.getData();
GoogleIdTokenCredential googleIdTokenCredential = GoogleIdTokenCredential.createFrom(credentialData);

// Sign in to Firebase with using the token
firebaseAuthWithGoogle(googleIdTokenCredential.getIdToken());
} else {
Log.w(TAG, "Credential is not of type Google ID!");
}
}

private void firebaseAuthWithGoogle(String idToken) {
AuthCredential credential = GoogleAuthProvider.getCredential(idToken, null);
mAuth.signInWithCredential(credential)
.addOnCompleteListener(requireActivity(), task -> {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success");
FirebaseUser user = mAuth.getCurrentUser();
updateUI(user);
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCredential:failure", task.getException());
Snackbar.make(mBinding.mainLayout, "Authentication Failed.", Snackbar.LENGTH_SHORT).show();
updateUI(null);
}

hideProgressBar();
});
}

private void signOut() {
// Firebase sign out
mAuth.signOut();

// Google sign out
signInClient.signOut().addOnCompleteListener(requireActivity(),
new OnCompleteListener<Void>() {
// When a user signs out, clear the current user credential state from all credential providers.
// This will notify all providers that any stored credential session for the given app should be cleared.
ClearCredentialStateRequest clearRequest = new ClearCredentialStateRequest();
credentialManager.clearCredentialStateAsync(
clearRequest,
new CancellationSignal(),
Executors.newSingleThreadExecutor(),
new CredentialManagerCallback<>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
public void onResult(@NonNull Void result) {
updateUI(null);
}

@Override
public void onError(@NonNull ClearCredentialException e) {
Log.e(TAG, "Couldn't clear user credentials: " + e.getLocalizedMessage());
}
});
}

private void updateUI(FirebaseUser user) {
hideProgressBar();
if (user != null) {
mBinding.status.setText(getString(R.string.google_status_fmt, user.getEmail()));
mBinding.detail.setText(getString(R.string.firebase_status_fmt, user.getUid()));

mBinding.signInButton.setVisibility(View.GONE);
mBinding.signOutButton.setVisibility(View.VISIBLE);
} else {
mBinding.status.setText(R.string.signed_out);
mBinding.detail.setText(null);

mBinding.signInButton.setVisibility(View.VISIBLE);
mBinding.signOutButton.setVisibility(View.GONE);
}
requireActivity().runOnUiThread(() -> {
hideProgressBar();
if (user != null) {
mBinding.status.setText(getString(R.string.google_status_fmt, user.getEmail()));
mBinding.detail.setText(getString(R.string.firebase_status_fmt, user.getUid()));

mBinding.signInButton.setVisibility(View.GONE);
mBinding.signOutButton.setVisibility(View.VISIBLE);
} else {
mBinding.status.setText(R.string.signed_out);
mBinding.detail.setText(null);

mBinding.signInButton.setVisibility(View.VISIBLE);
mBinding.signOutButton.setVisibility(View.GONE);
}
});
}

@Override
Expand Down
Loading