Skip to content

Credman Helper#115

Open
wickedcube wants to merge 3 commits into
mainfrom
PGS-migration-helper-credman
Open

Credman Helper#115
wickedcube wants to merge 3 commits into
mainfrom
PGS-migration-helper-credman

Conversation

@wickedcube
Copy link
Copy Markdown
Contributor

Credman implementation in Java to support migration from PGS v1 to v2

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request replaces the legacy Google Sign-In V2 implementation with a new Credential Manager (CredMan) integration via a Java bridge (CredManBridge.java), updating AuthManager.cs to handle silent and interactive sign-in flows and manage session caching. The review feedback highlights several critical issues: a shadowed webClientId variable in AuthManager.cs that will fail authentication, an unhandled SilentFailed error that causes a soft-lock, invalid '#' comments and a non-existent hasResolution() method in the Java bridge that will cause compilation failures, and potential thread leaks from creating new executors on every sign-in call.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +392 to +398
string webClientId = "";
AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
AndroidJavaClass bridge = new AndroidJavaClass("com.gamesamples.trivialkartunity.CredManBridge");

googleTaskComplete = true;
string methodName = interactive ? "signInInteractive" : "signInSilent";
bridge.CallStatic(methodName, currentActivity, webClientId);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The local variable webClientId is declared as an empty string "", which shadows the class field webClientId (defined at line 61). This causes an empty client ID to be passed to the Java bridge, which will fail to authenticate or retrieve the server auth code. We should remove the local declaration and use the class field this.webClientId.

        AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
        AndroidJavaClass bridge = new AndroidJavaClass("com.gamesamples.trivialkartunity.CredManBridge");
        
        string methodName = interactive ? "signInInteractive" : "signInSilent";
        bridge.CallStatic(methodName, currentActivity, this.webClientId);

Comment on lines +187 to 192
if (!string.IsNullOrEmpty(credManError))
{
// --- Success case ---
Debug.Log($"Google Sign-In successful for: {this.googleUser.Email}");
Debug.Log($"Retrieved Server Auth Code. Sending to backend...");
statusText.text = "Connecting to game server...";
StartCoroutine(ExchangeAuthcodeAndLink(authCodeToExchange));
Debug.LogError("CredMan Error: " + credManError);
statusText.text = "Sign-in Failed.";
ShowStartPanel();
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

If silent sign-in fails, OnSignInError is called with "SilentFailed". Currently, this error is ignored and does not trigger the main thread dispatcher to show the start panel. As a result, the game will soft-lock on the loading screen. We should handle "SilentFailed" gracefully by showing the start panel and updating the status text to "Please sign in.".

            if (!string.IsNullOrEmpty(credManError))
            {
                Debug.LogError("CredMan Error: " + credManError);
                statusText.text = credManError == "SilentFailed" ? "Please sign in." : "Sign-in Failed.";
                ShowStartPanel();
            }

Comment on lines +402 to 406
public void OnSignInError(string error)
{
if (error == "SilentFailed") { Debug.Log("Silent failed. Idle."); return; }
credManError = error; googleTaskComplete = true;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Returning early when error == "SilentFailed" prevents the main thread from being notified of the failure, leading to a soft-lock. We should set credManError and googleTaskComplete for all errors so the main thread can handle them and show the appropriate UI.

    public void OnSignInError(string error) 
    {
        credManError = error;
        googleTaskComplete = true;
    }

Log.i("CredMan", "PGS v1: Existing grant found. Returning user detected. Auth Code retrieved.");
UnityPlayer.UnitySendMessage("AuthManager", "OnSignInSuccess", authorizationResult.getServerAuthCode());
}
else if (authorizationResult.hasResolution()) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The AuthorizationResult class does not have a hasResolution() method. To check if a resolution is available, you should check if getPendingIntent() is not null. Using hasResolution() will cause a compilation error.

                    else if (authorizationResult.getPendingIntent() != null) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +34 to +41
public class CredManBridge {

// --- MODE 1: SILENT SIGN-IN (Called on Awake) ---
// Tries to auto-select an authorized account. If it fails, it does NOT show UI.
public static void signInSilent(Context context, String webClientId) {
CredentialManager credentialManager = CredentialManager.create(context);
CancellationSignal cancellationSignal = new CancellationSignal();
Executor executor = Executors.newSingleThreadExecutor();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Creating a new single-thread executor on every call to signInSilent (and signInInteractive) is inefficient and can lead to thread leaks since these executors are never shut down. We should define a single static Executor at the class level and reuse it.

public class CredManBridge {

    private static final Executor executor = Executors.newSingleThreadExecutor();

    // --- MODE 1: SILENT SIGN-IN (Called on Awake) ---
    // Tries to auto-select an authorized account. If it fails, it does NOT show UI.
    public static void signInSilent(Context context, String webClientId) {
        CredentialManager credentialManager = CredentialManager.create(context);
        CancellationSignal cancellationSignal = new CancellationSignal();

public static void signInInteractive(Context context, String webClientId) {
CredentialManager credentialManager = CredentialManager.create(context);
CancellationSignal cancellationSignal = new CancellationSignal();
Executor executor = Executors.newSingleThreadExecutor();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since we introduced a shared static executor at the class level, we should remove the local executor instantiation here to avoid shadowing and reuse the shared one.

        // Using the shared static executor

import java.util.concurrent.Executors;


# [START google_signin_credman_example]
Copy link
Copy Markdown
Contributor

@borisf borisf Jun 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to follow up with the DAC team, as this code will not compile

Can do a multiline comment (look below) , or a custom doclet (not 100% sure)

/*

[END google_signin_credman_example]

*/

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was requested by our tech writing team for linking to DAC

String email = credential.getId();

Account account = new Account(email, "com.google");
// Requesting GAMES_LITE scope to check for pre-existing V1 grants
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update the line to "pre-existing PGS V1 grants" + possible link


Account account = new Account(email, "com.google");
// Requesting GAMES_LITE scope to check for pre-existing V1 grants
List<Scope> requestedScopes = Collections.singletonList(new Scope("https://www.googleapis.com/auth/games_lite"));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make it a constant

Log.i("CredMan", "PGS v1: Existing grant found. Returning user detected. Auth Code retrieved.");
UnityPlayer.UnitySendMessage("AuthManager", "OnSignInSuccess", authorizationResult.getServerAuthCode());
}
else if (authorizationResult.hasResolution()) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private GoogleSignInUser googleUser;

// --- NEW VARIABLES for main-thread dispatching ---
// V2 (CredMan) Specific Variables
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PGS v2 + link

private void Update()
{
#if PGS_V2
// V2 Main Thread Dispatcher
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PGS v2


GoogleSignIn.DefaultInstance.SignOut();
ShowStartPanel();
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this, mismatched braces?

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants