Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
6 changes: 6 additions & 0 deletions packages/google_sign_in/google_sign_in_android/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 7.2.14

* Fixes an `IllegalStateException` ("Reply already submitted") crash when an authorization activity
result for `REQUEST_CODE_AUTHORIZE` is delivered more than once (for example after a configuration
change or process death), by clearing the pending callback before resolving it.
Comment thread
stuartmorgan-g marked this conversation as resolved.
Resolved

## 7.2.13

* Bumps com.google.android.gms:play-services-auth from 21.5.1 to 21.6.0.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -487,22 +487,26 @@ public void revokeAccess(
public boolean onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (requestCode == REQUEST_CODE_AUTHORIZE) {
if (pendingAuthorizationCallback != null) {
// Clear the pending callback before completing it so a re-delivered result (e.g. after a
// configuration change or process death) cannot complete the same reply twice.
Function1<? super Result<? extends AuthorizeResult>, Unit> callback =
pendingAuthorizationCallback;
pendingAuthorizationCallback = null;
try {
AuthorizationResult authorizationResult =
authorizationClientFactory.create(context).getAuthorizationResultFromIntent(data);
ResultUtilsKt.completeWithValue(
pendingAuthorizationCallback,
callback,
new PlatformAuthorizationResult(
authorizationResult.getAccessToken(),
authorizationResult.getServerAuthCode(),
authorizationResult.getGrantedScopes()));
return true;
} catch (ApiException e) {
ResultUtilsKt.completeWithValue(
pendingAuthorizationCallback,
callback,
new AuthorizeFailure(AuthorizeFailureType.API_EXCEPTION, e.getMessage(), null));
}
pendingAuthorizationCallback = null;
} else {
Log.e("google_sign_in", "Unexpected authorization result callback");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package io.flutter.plugins.googlesignin;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
Expand Down Expand Up @@ -992,6 +993,57 @@ public void authorize_returnsPostIntentResult() {
assertTrue(callbackCalled[0]);
}

// Regression test for https://github.com/flutter/flutter/issues/188062
// A re-delivered authorization activity result for REQUEST_CODE_AUTHORIZE (e.g. after a
// configuration change or process death) must not resolve the same callback twice, which would
// throw IllegalStateException ("Reply already submitted") on the real Pigeon reply.
@Test
public void authorize_ignoresDuplicateActivityResult() {
final List<String> scopes = new ArrayList<>(Arrays.asList("scope1", "scope1"));
PlatformAuthorizationRequest params =
new PlatformAuthorizationRequest(scopes, null, null, null);

final String accessToken = "accessToken";
final String serverAuthCode = "serverAuthCode";
when(mockAuthorizationClient.authorize(any())).thenReturn(mockAuthorizationTask);
AuthorizationResult successResult =
mockSuccessAuthorizationResult(serverAuthCode, accessToken, scopes);
try {
when(mockAuthorizationClient.getAuthorizationResultFromIntent(any()))
.thenReturn(successResult);
} catch (ApiException e) {
fail();
}

plugin.setActivity(mockActivity);
final int[] callbackCount = new int[] {0};
plugin.authorize(
params,
true,
ResultCompat.asCompatCallback(
reply -> {
callbackCount[0] += 1;
return null;
}));

@SuppressWarnings("unchecked")
ArgumentCaptor<OnSuccessListener<AuthorizationResult>> callbackCaptor =
ArgumentCaptor.forClass(OnSuccessListener.class);
verify(mockAuthorizationTask).addOnSuccessListener(callbackCaptor.capture());
callbackCaptor.getValue().onSuccess(mockResolutionAuthorizationResult(mockAuthorizationIntent));

// The first delivery resolves the authorization and is consumed.
boolean firstHandled =
plugin.onActivityResult(GoogleSignInPlugin.Delegate.REQUEST_CODE_AUTHORIZE, 0, null);
// A duplicate/re-delivered result for the same request code must be ignored, not re-resolved.
boolean secondHandled =
plugin.onActivityResult(GoogleSignInPlugin.Delegate.REQUEST_CODE_AUTHORIZE, 0, null);

assertTrue(firstHandled);
assertFalse(secondHandled);
assertEquals(1, callbackCount[0]);
}

@Test
public void authorize_reportsPendingIntentException() {
final List<String> scopes = new ArrayList<>(Arrays.asList("scope1", "scope1"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: google_sign_in_android
description: Android implementation of the google_sign_in plugin.
repository: https://github.com/flutter/packages/tree/main/packages/google_sign_in/google_sign_in_android
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22
version: 7.2.13
version: 7.2.14

environment:
sdk: ^3.12.0
Expand Down
Loading