Search code examples
androidauthenticationgoogle-plusgoogle-api-clientgoogle-fit

Multiple GoogleApiClient not firing connect()


TL;DR; GoogleFit Api client does not connect if is signed in with Google+

So... I'm facing a problem when using GoogleFit and Google+ api together. I am using Google+ to sign in a user and using GoogleFit to retrieve fitness.

Besides Google+ I have several other login options such as Facebook and Twitter. My problem is that if a user is signed in with Google+ the user can no longer connect to the Google Fit client. Basically when the button to connect to GoogleFit is pressed nothing happens. IF the user authenticates with Facebook or Twitter the GoogleFit client can connect just fine...

Here are some relevant code from this activity:

Google+ client:

 private GoogleApiClient buildGoogleApiClient() {
    return new GoogleApiClient.Builder(this)    
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(Plus.API)
            .addScope(Plus.SCOPE_PLUS_LOGIN)
            .addScope(Plus.SCOPE_PLUS_PROFILE)
            .build();
}

Google Fit client, this method is called whenever the user press the button to link GoogleFit to the app:

public void buildFitnessClient(Button b) {
    // Create the Google API Client
    fitConnectButton = b;
    mClient = new GoogleApiClient.Builder(this)
            .addApi(Fitness.API)
            .addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build();
    mClient.connect();
}

Lifecycle stuff:

 @Override
public void onConnected(Bundle bundle) {
    mSignInClicked = false;

    if(mGoogleServices != null) {
        Plus.PeopleApi.loadVisible(mGoogleServices, null).setResultCallback(this);
        userData = getProfileInformation();
    }
    if (hasWearDevice) mClient.connect();
}
 @Override
protected void onStart() {
    super.onStart();
    // Connect to G+ api
    if(mGoogleServices != null) mGoogleServices.connect();
    // Connect to the Fitness API
    if (hasWearDevice) mClient.connect();
}

@Override
public void onStop() {
    super.onStop();
    if(mGoogleServices != null) {
        if(mGoogleServices.isConnected()) mGoogleServices.disconnect();
    }
    if(hasWearDevice) {
        if(mClient.isConnected()) mClient.disconnect();
    }
}

Any suggestions?


Solution

  • I ended up solving my problems by using different callback and connectionFailed listeners for each one of the clients.

    My builder for the GoogleFitClient ended up looking like this:

    public void startFitnessClient() {
        mGoogleFitClient = new GoogleApiClient.Builder(this)
                .addApi(Fitness.API)
                .addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
                .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
                    @Override
                    public void onConnected(Bundle bundle) {
                        if (hasWearDevice) mGoogleFitClient.connect();
                    }
    
                    @Override
                    public void onConnectionSuspended(int i) {
                        if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) {
                            Log.i(LOG_TAG, "Connection lost.  Cause: Network Lost.");
                        } else if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
                            Log.i(LOG_TAG, "Connection lost.  Reason: Service Disconnected");
                        }
                    }
                })
                .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
                    @Override
                    public void onConnectionFailed(ConnectionResult connectionResult) {
                        // The failure has a resolution. Resolve it.
                        // Called typically when the app is not yet authorized, and an
                        // authorization dialog is displayed to the user.
                        if (!authInProgress) {
                            try {
                                Log.i(LOG_TAG, "Attempting to resolve failed connection");
                                authInProgress = true;
                                connectionResult.startResolutionForResult(BaseActivity.this, REQUEST_OAUTH);
                            } catch (IntentSender.SendIntentException e) {
                                Log.e(LOG_TAG, "Exception while starting resolution activity", e);
                                Crashlytics.logException(e);
                            }
                        }
                    }
                })
                .build();
    }
    

    And this is my client for the Google+ client.

    private void buildGoogleApiClient() {
        mGooglePlusClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
                    @Override
                    public void onConnected(Bundle bundle) {
                        mSignInClicked = false;
    
                        if(mGooglePlusClient != null) {
                            Plus.PeopleApi.loadVisible(mGooglePlusClient, null).setResultCallback(BaseActivity.this);
                            userData = getProfileInformation();
                        }
                    }
    
                    @Override
                    public void onConnectionSuspended(int i) {
                        mGooglePlusClient.connect();
                    }
                })
                .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
                    @Override
                    public void onConnectionFailed(ConnectionResult connectionResult) {
                        mConnectionResult = connectionResult;
                        if (!connectionResult.hasResolution()) {
                            GooglePlayServicesUtil.getErrorDialog(connectionResult.getErrorCode(), BaseActivity.this, 0).show();
                            return;
                        }
    
                        if (!mIntentInProgress) {
                            if (mSignInClicked) {
                                resolveSignInError();
                            }
                        }
                    }
                })
                .addApi(Plus.API)
                .addScope(Plus.SCOPE_PLUS_LOGIN)
                .addScope(Plus.SCOPE_PLUS_PROFILE)
                .build();
    }
    

    For what I observed by Logging every step of the process while debugging is that the authentication intent call happens inside onConnectionFailed with the call to startResolutionForResult and when they were sharing the same callback listeners once the Google+ client was connected that callback was never made by the GoogleFit client. By splitting both of them it's being guarantee that they are being called now.