GoogleSignIn.getLastSignedInAccount
is deprecated.
May I know, what is the alternative when migrating to Credential Manager API / Authorization API?
Currently, I do not use Credential Manager API.
I am using Authorization API to perform client login based on code snippet - https://developers.google.com/identity/authorization/android
List<Scopes> requestedScopes = Arrays.asList(DriveScopes.DRIVE_APPDATA);
AuthorizationRequest authorizationRequest = AuthorizationRequest.builder().setRequestedScopes(requestedScopes).build();
Identity.getAuthorizationClient(this)
.authorize(authorizationRequest)
.addOnSuccessListener(
authorizationResult -> {
if (authorizationResult.hasResolution()) {
// Access needs to be granted by the user
PendingIntent pendingIntent = authorizationResult.getPendingIntent();
try {
// This code will enable user to perform login.
startIntentSenderForResult(pendingIntent.getIntentSender(),
REQUEST_AUTHORIZE, null, 0, 0, 0, null);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Couldn't start Authorization UI: " + e.getLocalizedMessage());
}
} else {
// Access already granted, continue with user action
saveToDriveAppFolder(authorizationResult);
}
})
.addOnFailureListener(e -> Log.e(TAG, "Failed to authorize", e));
How I can get the last login account information?
I have tried the following code snippet from AI. But, it is not what I want. The following code snippet, will prompt a login dialog. What I want to do, is silently retrieve the last login account I use to access Google Drive.
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.credentials.CredentialManager;
import androidx.credentials.CredentialManagerCallback;
import androidx.credentials.GetCredentialRequest;
import androidx.credentials.GetCredentialResponse;
import androidx.credentials.exceptions.GetCredentialException;
import com.google.android.libraries.identity.googleid.GetGoogleIdOption;
import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential;
public class AuthManager {
private final Context context;
private final CredentialManager credentialManager;
public AuthManager(Context context) {
this.context = context;
this.credentialManager = CredentialManager.create(context);
}
public interface AuthCallback {
void onSuccess(GoogleIdTokenCredential credential);
void onFailure(Exception e);
}
public void getLastSignedInAccount(AuthCallback callback) {
GetGoogleIdOption googleIdOption = new GetGoogleIdOption.Builder()
.setServerClientId(WENOTE_CLOUD_STORAGE_CLIENT_ID)
.build();
GetCredentialRequest request = new GetCredentialRequest.Builder()
.addCredentialOption(googleIdOption)
.build();
android.util.Log.i("CHEOK", "Call getCredentialAsync");
credentialManager.getCredentialAsync(
context,
request,
null, // pass in a CancelationSignal to allow cancelling the request
Runnable::run, // Execute the callback immediately
new CredentialManagerCallback<GetCredentialResponse, GetCredentialException>() {
@Override
public void onResult(@NonNull GetCredentialResponse result) {
android.util.Log.i("CHEOK", "onResult " + result);
if (result != null) {
GoogleIdTokenCredential credential = (GoogleIdTokenCredential) result.getCredential();
callback.onSuccess(credential);
} else {
callback.onFailure(new Exception("No credential found"));
}
}
@Override
public void onError(@NonNull GetCredentialException e) {
android.util.Log.i("CHEOK", "onError " + e);
// Handle errors
callback.onFailure(e);
}
}
);
}
}
Another approach I have been trying is using Identity.getAuthorizationClient
. But, it is giving me null all-time-time.
private void xxx() {
Log.i("CHEOK", "xxx");
List<Scope> requestedScopes = Arrays.asList(
new Scope(DriveScopes.DRIVE_APPDATA),
new Scope("email"),
new Scope("profile"),
new Scope("openid")
);
AuthorizationRequest authorizationRequest = AuthorizationRequest.builder()
.setRequestedScopes(requestedScopes)
.build();
Identity.getAuthorizationClient(getContext())
.authorize(authorizationRequest)
.addOnSuccessListener(authorizationResult -> {
if (!authorizationResult.hasResolution()) {
// No user intervention required, we have the user details
GoogleSignInAccount account = authorizationResult.toGoogleSignInAccount();
Log.i("CHEOK", "Email = " + account.getEmail());
Log.i("CHEOK", "getDisplayName = " + account.getDisplayName());
Log.i("CHEOK", "getId = " + account.getId());
Log.i("CHEOK", "getIdToken = " + account.getIdToken());
}
})
.addOnFailureListener(e -> Log.e("CHEOK", "Failed to authorize", e));
}
There is no replacement for that API in the Identity or CredentialManager worlds. Here is what I suggest you do:
setFilterByAuthorizedAccounts(true)
and setAutoSelectEnabled(true)
.setFilterByAuthorizedAccounts(false)
which shows a bottomsheet to the user with all accounts listed so your user can select an account and sign up/in to your app. You will get an ID Token that has the above information.Authorization
APIs and only ask for Drive access. Since your user is already signed in, they are not going to see an account selector. If they have previously given consent to access their Drive, you immediately get back a response that has an AccessToken. If they haven't given consent, they see a consent page and if they accept, you get an AccessToken.Now let's see how this works: if a user is new, following the above flow results in seeing the bottomsheet, user selects an account and you get an ID Token that has the user information (so you take a note of that), they go in and at the right moment, you prompt them for Drive access, they accept the consent and you get an AccessToken. So all is good for that flow. Now, the next time the user opens your app, you do the same as above but this time, since the user had previously signed into your app, they will not be prompted with the bottomsheet as before; instead they see a bottomsheet that only shows up for a second or two, telling the user that he/she is being signed in (and requires no interaction from the user) and disappears on its own and you will get an ID Token which has the user info (which you will take a note of it) and again when you reach the appropriate moment, you call, as outlined above, the Authorization
APIs but this time you get an AccessToken immediately (with no user interaction required) and you are good to go.
Does this flow give you what you want?