diff --git a/packages/google_sign_in/google_sign_in_android/CHANGELOG.md b/packages/google_sign_in/google_sign_in_android/CHANGELOG.md index 35af262af52..75dcc58af33 100644 --- a/packages/google_sign_in/google_sign_in_android/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.1.34 + +* Removes unnecessary native code. + ## 6.1.33 * Updates Pigeon for non-nullable collection type support. diff --git a/packages/google_sign_in/google_sign_in_android/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java b/packages/google_sign_in/google_sign_in_android/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java index 301642bce1e..92f3f9927df 100644 --- a/packages/google_sign_in/google_sign_in_android/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java +++ b/packages/google_sign_in/google_sign_in_android/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java @@ -31,14 +31,11 @@ import io.flutter.embedding.engine.plugins.activity.ActivityAware; import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.PluginRegistry; import io.flutter.plugins.googlesignin.Messages.FlutterError; import io.flutter.plugins.googlesignin.Messages.GoogleSignInApi; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; @@ -111,241 +108,16 @@ public void onDetachedFromActivity() { disposeActivity(); } - // TODO(stuartmorgan): Remove this, and convert the unit tests to IDelegate tests. This is left - // here only to allow the existing tests to continue to work unchanged during the Pigeon migration - // to ensure that the refactoring didn't change any behavior, and is not actually used by the - // plugin. - @VisibleForTesting - void onMethodCall( - @NonNull io.flutter.plugin.common.MethodCall call, @NonNull MethodChannel.Result result) { - switch (call.method) { - case "init": - String signInOption = Objects.requireNonNull(call.argument("signInOption")); - List requestedScopes = Objects.requireNonNull(call.argument("scopes")); - String hostedDomain = call.argument("hostedDomain"); - String clientId = call.argument("clientId"); - String serverClientId = call.argument("serverClientId"); - boolean forceCodeForRefreshToken = - Objects.requireNonNull(call.argument("forceCodeForRefreshToken")); - delegate.init( - result, - signInOption, - requestedScopes, - hostedDomain, - clientId, - serverClientId, - forceCodeForRefreshToken); - break; - - case "signInSilently": - delegate.signInSilently(result); - break; - - case "signIn": - delegate.signIn(result); - break; - - case "getTokens": - String email = Objects.requireNonNull(call.argument("email")); - boolean shouldRecoverAuth = Objects.requireNonNull(call.argument("shouldRecoverAuth")); - delegate.getTokens(result, email, shouldRecoverAuth); - break; - - case "signOut": - delegate.signOut(result); - break; - - case "clearAuthCache": - String token = Objects.requireNonNull(call.argument("token")); - delegate.clearAuthCache(result, token); - break; - - case "disconnect": - delegate.disconnect(result); - break; - - case "isSignedIn": - delegate.isSignedIn(result); - break; - - case "requestScopes": - List scopes = Objects.requireNonNull(call.argument("scopes")); - delegate.requestScopes(result, scopes); - break; - - default: - result.notImplemented(); - } - } - - /** - * A delegate interface that exposes all of the sign-in functionality for other plugins to use. - * The below {@link Delegate} implementation should be used by any clients unless they need to - * override some of these functions, such as for testing. - */ - public interface IDelegate { - /** Initializes this delegate so that it is ready to perform other operations. */ - void init( - @NonNull MethodChannel.Result result, - @NonNull String signInOption, - @NonNull List requestedScopes, - @Nullable String hostedDomain, - @Nullable String clientId, - @Nullable String serverClientId, - boolean forceCodeForRefreshToken); - - /** - * Returns the account information for the user who is signed in to this app. If no user is - * signed in, tries to sign the user in without displaying any user interface. - */ - void signInSilently(@NonNull MethodChannel.Result result); - - /** - * Signs the user in via the sign-in user interface, including the OAuth consent flow if scopes - * were requested. - */ - void signIn(@NonNull MethodChannel.Result result); - - /** - * Gets an OAuth access token with the scopes that were specified during initialization for the - * user with the specified email address. - * - *

If shouldRecoverAuth is set to true and user needs to recover authentication for method to - * complete, the method will attempt to recover authentication and rerun method. - */ - void getTokens( - final @NonNull MethodChannel.Result result, - final @NonNull String email, - final boolean shouldRecoverAuth); - - /** - * Clears the token from any client cache forcing the next {@link #getTokens} call to fetch a - * new one. - */ - void clearAuthCache(final @NonNull MethodChannel.Result result, final @NonNull String token); - - /** - * Signs the user out. Their credentials may remain valid, meaning they'll be able to silently - * sign back in. - */ - void signOut(@NonNull MethodChannel.Result result); - - /** Signs the user out, and revokes their credentials. */ - void disconnect(@NonNull MethodChannel.Result result); - - /** Checks if there is a signed in user. */ - void isSignedIn(@NonNull MethodChannel.Result result); - - /** Prompts the user to grant an additional Oauth scopes. */ - void requestScopes( - final @NonNull MethodChannel.Result result, final @NonNull List scopes); - } - - /** - * Helper class for supporting the legacy IDelegate interface based on raw method channels, which - * handles converting any FlutterErrors (or other {@code Throwable}s in case any non- FlutterError - * exceptions slip through) thrown by the new code paths into {@code error} callbacks. - */ - private abstract static class ErrorConvertingMethodChannelVoidResult - implements Messages.VoidResult { - final @NonNull MethodChannel.Result result; - - public ErrorConvertingMethodChannelVoidResult(@NonNull MethodChannel.Result result) { - this.result = result; - } - - @Override - public void error(@NonNull Throwable error) { - if (error instanceof FlutterError) { - FlutterError flutterError = (FlutterError) error; - result.error(flutterError.code, flutterError.getMessage(), flutterError.details); - } else { - result.error("exception", error.getMessage(), null); - } - } - } - - /** - * Helper class for supporting the legacy IDelegate interface based on raw method channels, which - * handles converting any FlutterErrors (or other {@code Throwable}s in case any non- FlutterError - * exceptions slip through) thrown by the new code paths into {@code error} callbacks. - * - * @param The Result type of the result to convert from. - */ - private abstract static class ErrorConvertingMethodChannelResult - implements Messages.Result { - final @NonNull MethodChannel.Result result; - - public ErrorConvertingMethodChannelResult(@NonNull MethodChannel.Result result) { - this.result = result; - } - - @Override - public void error(@NonNull Throwable error) { - if (error instanceof FlutterError) { - FlutterError flutterError = (FlutterError) error; - result.error(flutterError.code, flutterError.getMessage(), flutterError.details); - } else { - result.error("exception", error.getMessage(), null); - } - } - } - - /** - * Helper class for supporting the legacy IDelegate interface based on raw method channels, which - * handles converting responses from methods that return {@code Messages.UserData}. - */ - private static class UserDataMethodChannelResult - extends ErrorConvertingMethodChannelResult { - public UserDataMethodChannelResult(MethodChannel.Result result) { - super(result); - } - - @Override - public void success(Messages.UserData data) { - Map response = new HashMap<>(); - response.put("email", data.getEmail()); - response.put("id", data.getId()); - response.put("idToken", data.getIdToken()); - response.put("serverAuthCode", data.getServerAuthCode()); - response.put("displayName", data.getDisplayName()); - if (data.getPhotoUrl() != null) { - response.put("photoUrl", data.getPhotoUrl()); - } - result.success(response); - } - } - - /** - * Helper class for supporting the legacy IDelegate interface based on raw method channels, which - * handles converting responses from methods that return {@code Void}. - */ - private static class VoidMethodChannelResult extends ErrorConvertingMethodChannelVoidResult { - public VoidMethodChannelResult(MethodChannel.Result result) { - super(result); - } - - @Override - public void success() { - result.success(null); - } - } - /** * Delegate class that does the work for the Google sign-in plugin. This is exposed as a dedicated * class for use in other plugins that wrap basic sign-in functionality. * *

All methods in this class assume that they are run to completion before any other method is - * invoked. In this context, "run to completion" means that their {@link MethodChannel.Result} - * argument has been completed (either successfully or in error). This class provides no - * synchronization constructs to guarantee such behavior; callers are responsible for providing - * such guarantees. + * invoked. In this context, "run to completion" means that their {@link Messages.Result} argument + * has been completed (either successfully or in error). This class provides no synchronization + * constructs to guarantee such behavior; callers are responsible for providing such guarantees. */ - // TODO(stuartmorgan): Remove this in a breaking change, replacing it with something using - // structured types rather than strings and dictionaries left over from the pre-Pigeon method - // channel implementation. - public static class Delegate - implements IDelegate, PluginRegistry.ActivityResultListener, GoogleSignInApi { + public static class Delegate implements PluginRegistry.ActivityResultListener, GoogleSignInApi { private static final int REQUEST_CODE_SIGNIN = 53293; private static final int REQUEST_CODE_RECOVER_AUTH = 53294; @VisibleForTesting static final int REQUEST_CODE_REQUEST_SCOPE = 53295; @@ -360,9 +132,6 @@ public static class Delegate private static final String ERROR_FAILURE_TO_RECOVER_AUTH = "failed_to_recover_auth"; private static final String ERROR_USER_RECOVERABLE_AUTH = "user_recoverable_auth"; - private static final String DEFAULT_SIGN_IN = "SignInOption.standard"; - private static final String DEFAULT_GAMES_SIGN_IN = "SignInOption.games"; - private final @NonNull Context context; // Only set activity for v2 embedder. Always access activity from getActivity() method. private @Nullable Activity activity; @@ -496,43 +265,6 @@ public void init(@NonNull Messages.InitParams params) { } } - // IDelegate version, for backwards compatibility. - @Override - public void init( - @NonNull MethodChannel.Result result, - @NonNull String signInOption, - @NonNull List requestedScopes, - @Nullable String hostedDomain, - @Nullable String clientId, - @Nullable String serverClientId, - boolean forceCodeForRefreshToken) { - try { - Messages.SignInType type; - switch (signInOption) { - case DEFAULT_GAMES_SIGN_IN: - type = Messages.SignInType.GAMES; - break; - case DEFAULT_SIGN_IN: - type = Messages.SignInType.STANDARD; - break; - default: - throw new IllegalStateException("Unknown signInOption"); - } - init( - new Messages.InitParams.Builder() - .setSignInType(type) - .setScopes(requestedScopes) - .setHostedDomain(hostedDomain) - .setClientId(clientId) - .setServerClientId(serverClientId) - .setForceCodeForRefreshToken(forceCodeForRefreshToken) - .build()); - result.success(null); - } catch (FlutterError e) { - result.error(e.code, e.getMessage(), e.details); - } - } - /** * Returns the account information for the user who is signed in to this app. If no user is * signed in, tries to sign the user in without displaying any user interface. @@ -549,12 +281,6 @@ public void signInSilently(@NonNull Messages.Result result) { } } - // IDelegate version, for backwards compatibility. - @Override - public void signInSilently(@NonNull MethodChannel.Result result) { - signInSilently(new UserDataMethodChannelResult(result)); - } - /** * Signs the user in via the sign-in user interface, including the OAuth consent flow if scopes * were requested. @@ -570,12 +296,6 @@ public void signIn(@NonNull Messages.Result result) { getActivity().startActivityForResult(signInIntent, REQUEST_CODE_SIGNIN); } - // IDelegate version, for backwards compatibility. - @Override - public void signIn(@NonNull MethodChannel.Result result) { - signIn(new UserDataMethodChannelResult(result)); - } - /** * Signs the user out. Their credentials may remain valid, meaning they'll be able to silently * sign back in. @@ -596,12 +316,6 @@ public void signOut(@NonNull Messages.VoidResult result) { }); } - // IDelegate version, for backwards compatibility. - @Override - public void signOut(@NonNull MethodChannel.Result result) { - signOut(new VoidMethodChannelResult(result)); - } - /** Signs the user out, and revokes their credentials. */ @Override public void disconnect(@NonNull Messages.VoidResult result) { @@ -619,12 +333,6 @@ public void disconnect(@NonNull Messages.VoidResult result) { }); } - // IDelegate version, for backwards compatibility. - @Override - public void disconnect(@NonNull MethodChannel.Result result) { - signOut(new VoidMethodChannelResult(result)); - } - /** Checks if there is a signed in user. */ @NonNull @Override @@ -632,12 +340,6 @@ public Boolean isSignedIn() { return GoogleSignIn.getLastSignedInAccount(context) != null; } - // IDelegate version, for backwards compatibility. - @Override - public void isSignedIn(final @NonNull MethodChannel.Result result) { - result.success(isSignedIn()); - } - @Override public void requestScopes( @NonNull List scopes, @NonNull Messages.Result result) { @@ -667,19 +369,6 @@ public void requestScopes( getActivity(), REQUEST_CODE_REQUEST_SCOPE, account, wrappedScopes.toArray(new Scope[0])); } - // IDelegate version, for backwards compatibility. - @Override - public void requestScopes(@NonNull MethodChannel.Result result, @NonNull List scopes) { - requestScopes( - scopes, - new ErrorConvertingMethodChannelResult(result) { - @Override - public void success(Boolean value) { - result.success(value); - } - }); - } - private void onSignInResult(Task completedTask) { try { GoogleSignInAccount account = completedTask.getResult(ApiException.class); @@ -816,13 +505,6 @@ public void clearAuthCache(@NonNull String token, @NonNull Messages.VoidResult r }); } - // IDelegate version, for backwards compatibility. - @Override - public void clearAuthCache( - final @NonNull MethodChannel.Result result, final @NonNull String token) { - clearAuthCache(token, new VoidMethodChannelResult(result)); - } - /** * Gets an OAuth access token with the scopes that were specified during initialization for the * user with the specified email address. @@ -884,25 +566,6 @@ public void getAccessToken( }); } - // IDelegate version, for backwards compatibility. - @Override - public void getTokens( - @NonNull final MethodChannel.Result result, - @NonNull final String email, - final boolean shouldRecoverAuth) { - getAccessToken( - email, - shouldRecoverAuth, - new ErrorConvertingMethodChannelResult(result) { - @Override - public void success(String value) { - HashMap tokenResult = new HashMap<>(); - tokenResult.put("accessToken", value); - result.success(tokenResult); - } - }); - } - @Override public boolean onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { if (pendingOperation == null) { diff --git a/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInLegacyMethodChannelTest.java b/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInLegacyMethodChannelTest.java deleted file mode 100644 index cd5b92217c6..00000000000 --- a/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInLegacyMethodChannelTest.java +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package io.flutter.plugins.googlesignin; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.res.Resources; -import com.google.android.gms.auth.api.signin.GoogleSignInAccount; -import com.google.android.gms.auth.api.signin.GoogleSignInClient; -import com.google.android.gms.auth.api.signin.GoogleSignInOptions; -import com.google.android.gms.common.api.ApiException; -import com.google.android.gms.common.api.CommonStatusCodes; -import com.google.android.gms.common.api.Scope; -import com.google.android.gms.common.api.Status; -import com.google.android.gms.tasks.Task; -import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; -import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; -import io.flutter.plugin.common.PluginRegistry; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.mockito.Spy; - -public class GoogleSignInLegacyMethodChannelTest { - @Mock Context mockContext; - @Mock Resources mockResources; - @Mock Activity mockActivity; - @Mock BinaryMessenger mockMessenger; - @Spy MethodChannel.Result result; - @Mock GoogleSignInWrapper mockGoogleSignIn; - @Mock GoogleSignInAccount account; - @Mock GoogleSignInClient mockClient; - @Mock Task mockSignInTask; - @Mock ActivityPluginBinding mockActivityPluginBinding; - - private GoogleSignInPlugin plugin; - private AutoCloseable mockCloseable; - - @Before - public void setUp() { - mockCloseable = MockitoAnnotations.openMocks(this); - when(mockContext.getResources()).thenReturn(mockResources); - when(mockActivityPluginBinding.getActivity()).thenReturn(mockActivity); - plugin = new GoogleSignInPlugin(); - plugin.initInstance(mockMessenger, mockContext, mockGoogleSignIn); - plugin.onAttachedToActivity(mockActivityPluginBinding); - } - - @After - public void tearDown() throws Exception { - mockCloseable.close(); - } - - @Test - public void requestScopes_ResultErrorIfAccountIsNull() { - HashMap> arguments = new HashMap<>(); - arguments.put("scopes", Collections.singletonList("requestedScope")); - MethodCall methodCall = new MethodCall("requestScopes", arguments); - when(mockGoogleSignIn.getLastSignedInAccount(mockContext)).thenReturn(null); - plugin.onMethodCall(methodCall, result); - verify(result).error("sign_in_required", "No account to grant scopes.", null); - } - - @Test - public void requestScopes_ResultTrueIfAlreadyGranted() { - HashMap> arguments = new HashMap<>(); - arguments.put("scopes", Collections.singletonList("requestedScope")); - - MethodCall methodCall = new MethodCall("requestScopes", arguments); - Scope requestedScope = new Scope("requestedScope"); - when(mockGoogleSignIn.getLastSignedInAccount(mockContext)).thenReturn(account); - when(account.getGrantedScopes()).thenReturn(Collections.singleton(requestedScope)); - when(mockGoogleSignIn.hasPermissions(account, requestedScope)).thenReturn(true); - - plugin.onMethodCall(methodCall, result); - verify(result).success(true); - } - - @Test - public void requestScopes_RequestsPermissionIfNotGranted() { - HashMap> arguments = new HashMap<>(); - arguments.put("scopes", Collections.singletonList("requestedScope")); - MethodCall methodCall = new MethodCall("requestScopes", arguments); - Scope requestedScope = new Scope("requestedScope"); - - when(mockGoogleSignIn.getLastSignedInAccount(mockContext)).thenReturn(account); - when(account.getGrantedScopes()).thenReturn(Collections.singleton(requestedScope)); - when(mockGoogleSignIn.hasPermissions(account, requestedScope)).thenReturn(false); - - plugin.onMethodCall(methodCall, result); - - verify(mockGoogleSignIn) - .requestPermissions(mockActivity, 53295, account, new Scope[] {requestedScope}); - } - - @Test - public void requestScopes_ReturnsFalseIfPermissionDenied() { - HashMap> arguments = new HashMap<>(); - arguments.put("scopes", Collections.singletonList("requestedScope")); - MethodCall methodCall = new MethodCall("requestScopes", arguments); - Scope requestedScope = new Scope("requestedScope"); - - ArgumentCaptor captor = - ArgumentCaptor.forClass(PluginRegistry.ActivityResultListener.class); - verify(mockActivityPluginBinding).addActivityResultListener(captor.capture()); - PluginRegistry.ActivityResultListener listener = captor.getValue(); - - when(mockGoogleSignIn.getLastSignedInAccount(mockContext)).thenReturn(account); - when(account.getGrantedScopes()).thenReturn(Collections.singleton(requestedScope)); - when(mockGoogleSignIn.hasPermissions(account, requestedScope)).thenReturn(false); - - plugin.onMethodCall(methodCall, result); - listener.onActivityResult( - GoogleSignInPlugin.Delegate.REQUEST_CODE_REQUEST_SCOPE, - Activity.RESULT_CANCELED, - new Intent()); - - verify(result).success(false); - } - - @Test - public void requestScopes_ReturnsTrueIfPermissionGranted() { - HashMap> arguments = new HashMap<>(); - arguments.put("scopes", Collections.singletonList("requestedScope")); - MethodCall methodCall = new MethodCall("requestScopes", arguments); - Scope requestedScope = new Scope("requestedScope"); - - ArgumentCaptor captor = - ArgumentCaptor.forClass(PluginRegistry.ActivityResultListener.class); - verify(mockActivityPluginBinding).addActivityResultListener(captor.capture()); - PluginRegistry.ActivityResultListener listener = captor.getValue(); - - when(mockGoogleSignIn.getLastSignedInAccount(mockContext)).thenReturn(account); - when(account.getGrantedScopes()).thenReturn(Collections.singleton(requestedScope)); - when(mockGoogleSignIn.hasPermissions(account, requestedScope)).thenReturn(false); - - plugin.onMethodCall(methodCall, result); - listener.onActivityResult( - GoogleSignInPlugin.Delegate.REQUEST_CODE_REQUEST_SCOPE, Activity.RESULT_OK, new Intent()); - - verify(result).success(true); - } - - @Test - public void requestScopes_mayBeCalledRepeatedly_ifAlreadyGranted() { - HashMap> arguments = new HashMap<>(); - arguments.put("scopes", Collections.singletonList("requestedScope")); - MethodCall methodCall = new MethodCall("requestScopes", arguments); - Scope requestedScope = new Scope("requestedScope"); - - ArgumentCaptor captor = - ArgumentCaptor.forClass(PluginRegistry.ActivityResultListener.class); - verify(mockActivityPluginBinding).addActivityResultListener(captor.capture()); - PluginRegistry.ActivityResultListener listener = captor.getValue(); - - when(mockGoogleSignIn.getLastSignedInAccount(mockContext)).thenReturn(account); - when(account.getGrantedScopes()).thenReturn(Collections.singleton(requestedScope)); - when(mockGoogleSignIn.hasPermissions(account, requestedScope)).thenReturn(false); - - plugin.onMethodCall(methodCall, result); - listener.onActivityResult( - GoogleSignInPlugin.Delegate.REQUEST_CODE_REQUEST_SCOPE, Activity.RESULT_OK, new Intent()); - plugin.onMethodCall(methodCall, result); - listener.onActivityResult( - GoogleSignInPlugin.Delegate.REQUEST_CODE_REQUEST_SCOPE, Activity.RESULT_OK, new Intent()); - - verify(result, times(2)).success(true); - } - - @Test - public void requestScopes_mayBeCalledRepeatedly_ifNotSignedIn() { - HashMap> arguments = new HashMap<>(); - arguments.put("scopes", Collections.singletonList("requestedScope")); - MethodCall methodCall = new MethodCall("requestScopes", arguments); - Scope requestedScope = new Scope("requestedScope"); - - ArgumentCaptor captor = - ArgumentCaptor.forClass(PluginRegistry.ActivityResultListener.class); - verify(mockActivityPluginBinding).addActivityResultListener(captor.capture()); - PluginRegistry.ActivityResultListener listener = captor.getValue(); - - when(mockGoogleSignIn.getLastSignedInAccount(mockContext)).thenReturn(null); - - plugin.onMethodCall(methodCall, result); - listener.onActivityResult( - GoogleSignInPlugin.Delegate.REQUEST_CODE_REQUEST_SCOPE, Activity.RESULT_OK, new Intent()); - plugin.onMethodCall(methodCall, result); - listener.onActivityResult( - GoogleSignInPlugin.Delegate.REQUEST_CODE_REQUEST_SCOPE, Activity.RESULT_OK, new Intent()); - - verify(result, times(2)).error("sign_in_required", "No account to grant scopes.", null); - } - - @Test(expected = IllegalStateException.class) - public void signInThrowsWithoutActivity() { - final GoogleSignInPlugin plugin = new GoogleSignInPlugin(); - plugin.initInstance( - mock(BinaryMessenger.class), mock(Context.class), mock(GoogleSignInWrapper.class)); - - plugin.onMethodCall(new MethodCall("signIn", null), null); - } - - @Test - public void signInSilentlyThatImmediatelyCompletesWithoutResultFinishesWithError() - throws ApiException { - final String clientId = "fakeClientId"; - MethodCall methodCall = buildInitMethodCall(clientId, null); - initAndAssertServerClientId(methodCall, clientId); - - ApiException exception = - new ApiException(new Status(CommonStatusCodes.SIGN_IN_REQUIRED, "Error text")); - when(mockClient.silentSignIn()).thenReturn(mockSignInTask); - when(mockSignInTask.isComplete()).thenReturn(true); - when(mockSignInTask.getResult(ApiException.class)).thenThrow(exception); - - plugin.onMethodCall(new MethodCall("signInSilently", null), result); - verify(result) - .error( - "sign_in_required", - "com.google.android.gms.common.api.ApiException: 4: Error text", - null); - } - - @Test - public void init_LoadsServerClientIdFromResources() { - final String packageName = "fakePackageName"; - final String serverClientId = "fakeServerClientId"; - final int resourceId = 1; - MethodCall methodCall = buildInitMethodCall(null, null); - when(mockContext.getPackageName()).thenReturn(packageName); - when(mockResources.getIdentifier("default_web_client_id", "string", packageName)) - .thenReturn(resourceId); - when(mockContext.getString(resourceId)).thenReturn(serverClientId); - initAndAssertServerClientId(methodCall, serverClientId); - } - - @Test - public void init_InterpretsClientIdAsServerClientId() { - final String clientId = "fakeClientId"; - MethodCall methodCall = buildInitMethodCall(clientId, null); - initAndAssertServerClientId(methodCall, clientId); - } - - @Test - public void init_ForwardsServerClientId() { - final String serverClientId = "fakeServerClientId"; - MethodCall methodCall = buildInitMethodCall(null, serverClientId); - initAndAssertServerClientId(methodCall, serverClientId); - } - - @Test - public void init_IgnoresClientIdIfServerClientIdIsProvided() { - final String clientId = "fakeClientId"; - final String serverClientId = "fakeServerClientId"; - MethodCall methodCall = buildInitMethodCall(clientId, serverClientId); - initAndAssertServerClientId(methodCall, serverClientId); - } - - @Test - public void init_PassesForceCodeForRefreshTokenFalseWithServerClientIdParameter() { - MethodCall methodCall = buildInitMethodCall("fakeClientId", "fakeServerClientId", false); - - initAndAssertForceCodeForRefreshToken(methodCall, false); - } - - @Test - public void init_PassesForceCodeForRefreshTokenTrueWithServerClientIdParameter() { - MethodCall methodCall = buildInitMethodCall("fakeClientId", "fakeServerClientId", true); - - initAndAssertForceCodeForRefreshToken(methodCall, true); - } - - @Test - public void init_PassesForceCodeForRefreshTokenFalseWithServerClientIdFromResources() { - final String packageName = "fakePackageName"; - final String serverClientId = "fakeServerClientId"; - final int resourceId = 1; - MethodCall methodCall = buildInitMethodCall(null, null, false); - when(mockContext.getPackageName()).thenReturn(packageName); - when(mockResources.getIdentifier("default_web_client_id", "string", packageName)) - .thenReturn(resourceId); - when(mockContext.getString(resourceId)).thenReturn(serverClientId); - - initAndAssertForceCodeForRefreshToken(methodCall, false); - } - - @Test - public void init_PassesForceCodeForRefreshTokenTrueWithServerClientIdFromResources() { - final String packageName = "fakePackageName"; - final String serverClientId = "fakeServerClientId"; - final int resourceId = 1; - MethodCall methodCall = buildInitMethodCall(null, null, true); - when(mockContext.getPackageName()).thenReturn(packageName); - when(mockResources.getIdentifier("default_web_client_id", "string", packageName)) - .thenReturn(resourceId); - when(mockContext.getString(resourceId)).thenReturn(serverClientId); - - initAndAssertForceCodeForRefreshToken(methodCall, true); - } - - public void initAndAssertServerClientId(MethodCall methodCall, String serverClientId) { - ArgumentCaptor optionsCaptor = - ArgumentCaptor.forClass(GoogleSignInOptions.class); - when(mockGoogleSignIn.getClient(any(Context.class), optionsCaptor.capture())) - .thenReturn(mockClient); - plugin.onMethodCall(methodCall, result); - verify(result).success(null); - Assert.assertEquals(serverClientId, optionsCaptor.getValue().getServerClientId()); - } - - public void initAndAssertForceCodeForRefreshToken( - MethodCall methodCall, boolean forceCodeForRefreshToken) { - ArgumentCaptor optionsCaptor = - ArgumentCaptor.forClass(GoogleSignInOptions.class); - when(mockGoogleSignIn.getClient(any(Context.class), optionsCaptor.capture())) - .thenReturn(mockClient); - plugin.onMethodCall(methodCall, result); - verify(result).success(null); - Assert.assertEquals( - forceCodeForRefreshToken, optionsCaptor.getValue().isForceCodeForRefreshToken()); - } - - private static MethodCall buildInitMethodCall(String clientId, String serverClientId) { - return buildInitMethodCall( - "SignInOption.standard", Collections.emptyList(), clientId, serverClientId, false); - } - - private static MethodCall buildInitMethodCall( - String clientId, String serverClientId, boolean forceCodeForRefreshToken) { - return buildInitMethodCall( - "SignInOption.standard", - Collections.emptyList(), - clientId, - serverClientId, - forceCodeForRefreshToken); - } - - private static MethodCall buildInitMethodCall( - String signInOption, - List scopes, - String clientId, - String serverClientId, - boolean forceCodeForRefreshToken) { - HashMap arguments = new HashMap<>(); - arguments.put("signInOption", signInOption); - arguments.put("scopes", scopes); - if (clientId != null) { - arguments.put("clientId", clientId); - } - if (serverClientId != null) { - arguments.put("serverClientId", serverClientId); - } - arguments.put("forceCodeForRefreshToken", forceCodeForRefreshToken); - return new MethodCall("init", arguments); - } -} diff --git a/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInTest.java b/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInTest.java index 45dbae35500..03853740b4e 100644 --- a/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInTest.java +++ b/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInTest.java @@ -22,7 +22,6 @@ import com.google.android.gms.common.api.Scope; import com.google.android.gms.common.api.Status; import com.google.android.gms.tasks.Task; -import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugins.googlesignin.Messages.FlutterError; import io.flutter.plugins.googlesignin.Messages.InitParams; import java.util.Collections; @@ -40,7 +39,6 @@ public class GoogleSignInTest { @Mock Context mockContext; @Mock Resources mockResources; @Mock Activity mockActivity; - @Mock BinaryMessenger mockMessenger; @Spy Messages.VoidResult voidResult; @Spy Messages.Result boolResult; @Spy Messages.Result userDataResult; diff --git a/packages/google_sign_in/google_sign_in_android/pubspec.yaml b/packages/google_sign_in/google_sign_in_android/pubspec.yaml index 598eeb91a9d..b47fba90059 100644 --- a/packages/google_sign_in/google_sign_in_android/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_android/pubspec.yaml @@ -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: 6.1.33 +version: 6.1.34 environment: sdk: ^3.5.0