I'm trying to implement Google sign in in order to use Wallet, or Pay, and sell a product to the user. I followed the steps from the official guide and I even cloned the project and it has the same issue as mine. The problem is that when I try to get the user's information from the OptionalPendingResult the system throws an IllegalStateException.
First, the user has to go through an Activity that uses a GoogleApiClient initialized this way:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_checkout);
ButterKnife.bind(this);
setSupportActionBar(toolbar);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Wallet.API, new Wallet.WalletOptions.Builder().build())
.build();
showProgressDialog();
itemInfo = getIntent().getParcelableExtra(Constants.EXTRA_ITEM_INFO);
}
Afterwards, I show a com.google.android.gms.common.SignInButton in a fragment hosted by an Activity without a GoogleApiClient which I'm implementing on the fragment:
public class LoginFragment extends Fragment implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
public static final int REQUEST_CODE_PICK_ACCOUNT = 1000;
public static final int REQUEST_CODE_RESOLVE_ERR = 1005;
public static final int REQUEST_CODE_SIGN_IN = 1006;
private static final String TAG = "LoginFragment";
private static final String WALLET_SCOPE = "https://www.googleapis.com/auth/payments.make_payments";
private static final String WALLET_SANDBOX_SCOPE = "https://www.googleapis.com/auth/paymentssandbox.make_payments";
@Bind(R.id.sign_in_button)com.google.android.gms.common.SignInButton button;
private ProgressDialog mProgressDialog;
private GoogleApiClient mGoogleApiClient;
private int mLoginAction;
private String userEmail;
public static LoginFragment newInstance(int intentCode) {
LoginFragment fragment = new LoginFragment();
Bundle args = new Bundle();
args.putInt(LoginActivity.EXTRA_ACTION, intentCode);
fragment.setArguments(args);
return fragment;
}
public LoginFragment() {}
@Override public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if (args != null) {
mLoginAction = args.getInt(LoginActivity.EXTRA_ACTION);
}
if(savedInstanceState != null) {
userEmail = savedInstanceState.getString("email");
}
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.requestProfile()
.requestScopes(new Scope(WALLET_SCOPE))
// .requestIdToken(getString(R.string.client_id_test))
.build();
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
}
@Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View v = inflater.inflate(R.layout.fragment_login, container, false);
ButterKnife.bind(this, v);
button.setSize(SignInButton.SIZE_WIDE);
if(savedInstanceState != null && userEmail.isEmpty())
userEmail = savedInstanceState.getString("email");
button.setClickable(true);
return v;
}
@Override public void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
@Override public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("email", userEmail);
}
@Override public void onStop() {
super.onStop();
mGoogleApiClient.disconnect();
}
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CODE_SIGN_IN:
logIn(data);
button.setClickable(true);
break;
case REQUEST_CODE_PICK_ACCOUNT:
if (resultCode == Activity.RESULT_OK) {
userEmail = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
getUsername();
} else if (resultCode == Activity.RESULT_CANCELED) {
showToast(getString(R.string.please_select_account));
}
default:
super.onActivityResult(requestCode, resultCode, data);
break;
}
}
@Override public void onDestroyView() {
super.onDestroyView();
ButterKnife.unbind(this);
mGoogleApiClient = null;
}
@OnClick(R.id.sign_in_button) public void onSignIn() {
if(button.isClickable()) {
button.setClickable(false);
Intent intent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(intent, REQUEST_CODE_SIGN_IN);
}
}
@Override public void onConnected(@Nullable Bundle bundle) {
if (mLoginAction == LoginActivity.Action.LOGOUT) {
logOut();
}
}
@Override public void onConnectionSuspended(int i) {}
@Override public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
Log.e(TAG, "onConnectionFailed, error code:" + connectionResult.getErrorCode());
switch (connectionResult.getErrorCode()) {
case ConnectionResult.SERVICE_DISABLED:
showToast(getString(R.string.error_gps_service_disabled));
break;
case ConnectionResult.SERVICE_INVALID:
showToast(getString(R.string.error_gps_service_invalid));
break;
case ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED:
showToast(getString(R.string.error_gps_service_update));
break;
}
}
private void showToast(String message) {
Toast.makeText(getActivity(), "Failed: " + message, Toast.LENGTH_SHORT).show();
}
private void logIn(Intent data) {
OptionalPendingResult<GoogleSignInResult> opr = Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient);
if (opr.isDone()) {
try {
GoogleSignInResult signInResult = opr.get();
GoogleSignInAccount gsa = signInResult.getSignInAccount();
Toast.makeText(getActivity(), getString(R.string.welcome_user, gsa.getDisplayName()),
Toast.LENGTH_LONG).show();
((MultaJustaApp) getActivity().getApplication()).login(gsa.getEmail(), gsa.getIdToken());
success = true;
} catch (IllegalStateException e) {
e.printStackTrace();
showToast(getString(R.string.error_sign_in));
}
} else {
showToast(getString(R.string.network_error));
}
if(success) {
getActivity().setResult(Activity.RESULT_OK);
getActivity().finish();
}
}
}
Worth mentioning that right after the creation of the opr, when I check it on watch variables it has a Status{statusCode=INTERNAL_ERROR, resolution=null} property, and of course when opr.get() is called the IllegalStateException is thrown because The Result has already been consumed. I've tried everything, the API is enabled in my console, the checksum from the keystore is up, and the apiClient is connected at the time of the request. I'm having the problem on both emulators and physical devices. I'm desperate. I really appreciate any help.
Thanks

