Commit 8f62d2e9 authored by Alice Wang's avatar Alice Wang Committed by Commit Bot

[Android][WebSignIn] Setup sign-in general error UI

This CL sets up the sign-in general error UI screen when web sign-in
encounters some general error like connection failed.

Bug: 1114589
Change-Id: I5f2784283be1e49c715840ee03fab8b7af864cf1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2360074Reviewed-by: default avatarMihai Sardarescu <msarda@chromium.org>
Reviewed-by: default avatarTanmoy Mollik <triploblastic@chromium.org>
Commit-Queue: Alice Wang <aliceywang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#799064}
parent a1c1c908
......@@ -17,6 +17,7 @@ import org.chromium.components.signin.AccountManagerFacade;
import org.chromium.components.signin.AccountManagerFacadeProvider;
import org.chromium.components.signin.AccountUtils;
import org.chromium.components.signin.AccountsChangeObserver;
import org.chromium.components.signin.base.GoogleServiceAuthError;
import org.chromium.ui.modelutil.PropertyModel;
import java.util.Collections;
......@@ -165,7 +166,13 @@ class AccountPickerBottomSheetMediator implements AccountPickerCoordinator.Liste
} else {
mModel.set(AccountPickerBottomSheetProperties.ACCOUNT_PICKER_BOTTOM_SHEET_STATE,
AccountPickerBottomSheetState.SIGNIN_IN_PROGRESS);
mAccountPickerDelegate.signIn(mSelectedAccountName);
mAccountPickerDelegate.signIn(mSelectedAccountName, this::onSignInError);
}
}
private void onSignInError(GoogleServiceAuthError error) {
// TODO(https://crbug.com/1116952): Implement UI for sign-in auth error
mModel.set(AccountPickerBottomSheetProperties.ACCOUNT_PICKER_BOTTOM_SHEET_STATE,
AccountPickerBottomSheetState.SIGNIN_GENERAL_ERROR);
}
}
......@@ -25,11 +25,14 @@ class AccountPickerBottomSheetProperties {
* Different account picker state correspond to different account picker bottom sheet
* configuration.
*/
@IntDef({AccountPickerBottomSheetState.NO_ACCOUNTS,
@IntDef({
AccountPickerBottomSheetState.NO_ACCOUNTS,
AccountPickerBottomSheetState.COLLAPSED_ACCOUNT_LIST,
AccountPickerBottomSheetState.EXPANDED_ACCOUNT_LIST,
AccountPickerBottomSheetState.SIGNIN_IN_PROGRESS,
AccountPickerBottomSheetState.INCOGNITO_INTERSTITIAL})
AccountPickerBottomSheetState.INCOGNITO_INTERSTITIAL,
AccountPickerBottomSheetState.SIGNIN_GENERAL_ERROR,
})
@Retention(RetentionPolicy.SOURCE)
@interface AccountPickerBottomSheetState {
/**
......@@ -77,6 +80,14 @@ class AccountPickerBottomSheetProperties {
* user has clicked the "Go incognito mode" option.
*/
int INCOGNITO_INTERSTITIAL = 4;
/**
* When user cannot complete sign-in due to connectivity issues for example, the
* general sign-in error screen will be shown.
*
* The state can be reached when an error appears during the sign-in process.
*/
int SIGNIN_GENERAL_ERROR = 5;
}
// PropertyKeys for the selected account view when the account list is collapsed.
......
......@@ -18,6 +18,7 @@ import org.chromium.chrome.R;
import org.chromium.chrome.browser.signin.DisplayableProfileData;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
import org.chromium.ui.widget.ButtonCompat;
import org.chromium.ui.widget.TextViewWithLeading;
/**
* This class is the AccountPickerBottomsheet view for the web sign-in flow.
......@@ -30,6 +31,7 @@ class AccountPickerBottomSheetView implements BottomSheetContent {
private final Context mContext;
private final View mContentView;
private final TextView mAccountPickerTitle;
private final TextViewWithLeading mAccountPickerSubtitle;
private final RecyclerView mAccountListView;
private final View mSelectedAccountView;
private final View mIncognitoInterstitialView;
......@@ -40,6 +42,8 @@ class AccountPickerBottomSheetView implements BottomSheetContent {
mContentView = LayoutInflater.from(mContext).inflate(
R.layout.account_picker_bottom_sheet_view, null);
mAccountPickerTitle = mContentView.findViewById(R.id.account_picker_bottom_sheet_title);
mAccountPickerSubtitle =
mContentView.findViewById(R.id.account_picker_bottom_sheet_subtitle);
mAccountListView = mContentView.findViewById(R.id.account_picker_account_list);
mIncognitoInterstitialView =
mContentView.findViewById(R.id.incognito_interstitial_bottom_sheet_view);
......@@ -120,8 +124,7 @@ class AccountPickerBottomSheetView implements BottomSheetContent {
*/
void setUpSignInInProgressView() {
mAccountPickerTitle.setText(R.string.signin_account_picker_bottom_sheet_signin_title);
mContentView.findViewById(R.id.account_picker_bottom_sheet_subtitle)
.setVisibility(View.GONE);
mAccountPickerSubtitle.setVisibility(View.GONE);
mContentView.findViewById(R.id.account_picker_horizontal_divider).setVisibility(View.GONE);
mSelectedAccountView.setVisibility(View.GONE);
mContinueAsButton.setVisibility(View.GONE);
......@@ -135,13 +138,24 @@ class AccountPickerBottomSheetView implements BottomSheetContent {
logo.setImageResource(R.drawable.location_bar_incognito_badge);
mAccountPickerTitle.setVisibility(View.GONE);
mContentView.findViewById(R.id.account_picker_bottom_sheet_subtitle)
.setVisibility(View.GONE);
mAccountPickerSubtitle.setVisibility(View.GONE);
mContentView.findViewById(R.id.account_picker_horizontal_divider).setVisibility(View.GONE);
mAccountListView.setVisibility(View.GONE);
mIncognitoInterstitialView.setVisibility(View.VISIBLE);
}
/**
* Sets up the view for sign-in general error.
*/
void setUpSignInGeneralErrorView() {
// TODO(https://crbug.com/1114589): Add subtitle string for sign-in general error
mAccountPickerSubtitle.setVisibility(View.VISIBLE);
mContentView.findViewById(R.id.account_picker_horizontal_divider).setVisibility(View.GONE);
mSelectedAccountView.setVisibility(View.GONE);
mContentView.findViewById(R.id.account_picker_signin_spinner_view).setVisibility(View.GONE);
}
@Override
public View getContentView() {
return mContentView;
......
......@@ -59,6 +59,9 @@ class AccountPickerBottomSheetViewBinder {
case AccountPickerBottomSheetState.INCOGNITO_INTERSTITIAL:
view.setUpIncognitoInterstitialView();
break;
case AccountPickerBottomSheetState.SIGNIN_GENERAL_ERROR:
view.setUpSignInGeneralErrorView();
break;
default:
throw new IllegalArgumentException(
"Cannot bind AccountPickerBottomSheetView for the state:"
......
......@@ -41,6 +41,7 @@ public class AccountPickerDelegate implements WebSigninBridge.Listener {
private final String mContinueUrl;
private final SigninManager mSigninManager;
private WebSigninBridge mWebSigninBridge;
private Callback<GoogleServiceAuthError> mOnSignInErrorCallback;
public AccountPickerDelegate(WindowAndroid windowAndroid, String continueUrl) {
mWindowAndroid = windowAndroid;
......@@ -64,9 +65,10 @@ public class AccountPickerDelegate implements WebSigninBridge.Listener {
/**
* Signs the user into the account of the given accountName.
*/
public void signIn(String accountName) {
public void signIn(String accountName, Callback<GoogleServiceAuthError> onSignInErrorCallback) {
Account account = AccountUtils.findAccountByName(
AccountManagerFacadeProvider.getInstance().tryGetGoogleAccounts(), accountName);
mOnSignInErrorCallback = onSignInErrorCallback;
mSigninManager.signIn(
SigninAccessPoint.WEB_SIGNIN, account, new SigninManager.SignInCallback() {
@Override
......@@ -126,11 +128,12 @@ public class AccountPickerDelegate implements WebSigninBridge.Listener {
public void onSigninSucceded() {}
/**
* TODO(https//crbug.com/1114589): Handle web sign-in errors.
* Sign-in process failed.
*
* @param error Details about the error that occurred in the sign-in process.
*/
@Override
public void onSigninFailed(GoogleServiceAuthError error) {}
public void onSigninFailed(GoogleServiceAuthError error) {
mOnSignInErrorCallback.onResult(error);
}
}
......@@ -18,7 +18,10 @@ import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.core.AllOf.allOf;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
import static org.mockito.MockitoAnnotations.initMocks;
......@@ -53,6 +56,8 @@ import org.chromium.chrome.test.util.browser.signin.AccountManagerTestRule;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
import org.chromium.components.signin.AccountManagerFacadeProvider;
import org.chromium.components.signin.ProfileDataSource;
import org.chromium.components.signin.base.GoogleServiceAuthError;
import org.chromium.components.signin.base.GoogleServiceAuthError.State;
import org.chromium.components.signin.test.util.FakeAccountManagerFacade;
import org.chromium.components.signin.test.util.FakeProfileDataSource;
import org.chromium.content_public.browser.test.util.CriteriaHelper;
......@@ -260,7 +265,7 @@ public class AccountPickerBottomSheetTest {
CriteriaHelper.pollUiThread(() -> {
return !bottomSheetView.findViewById(R.id.account_picker_continue_as_button).isShown();
});
verify(mAccountPickerDelegateMock).signIn(PROFILE_DATA1.getAccountName());
verify(mAccountPickerDelegateMock).signIn(eq(PROFILE_DATA1.getAccountName()), any());
Assert.assertTrue(
bottomSheetView.findViewById(R.id.account_picker_signin_spinner_view).isShown());
// Currently the ProgressBar animation cannot be disabled on android-marshmallow-arm64-rel
......@@ -295,7 +300,34 @@ public class AccountPickerBottomSheetTest {
CriteriaHelper.pollUiThread(() -> {
return !bottomSheetView.findViewById(R.id.account_picker_continue_as_button).isShown();
});
verify(mAccountPickerDelegateMock).signIn(PROFILE_DATA2.getAccountName());
verify(mAccountPickerDelegateMock).signIn(eq(PROFILE_DATA2.getAccountName()), any());
}
@Test
@MediumTest
public void testSignInGeneralError() {
// Throws a connection error during the sign-in action
doAnswer(invocation -> {
Callback<GoogleServiceAuthError> onSignInErrorCallback = invocation.getArgument(1);
onSignInErrorCallback.onResult(new GoogleServiceAuthError(State.CONNECTION_FAILED));
return null;
})
.when(mAccountPickerDelegateMock)
.signIn(eq(PROFILE_DATA1.getAccountName()), any());
buildAndShowCollapsedBottomSheet();
View bottomSheetView = mCoordinator.getBottomSheetViewForTesting();
ThreadUtils.runOnUiThread(
bottomSheetView.findViewById(R.id.account_picker_continue_as_button)::performClick);
CriteriaHelper.pollUiThread(() -> {
return !bottomSheetView.findViewById(R.id.account_picker_selected_account).isShown()
&& bottomSheetView.findViewById(R.id.account_picker_bottom_sheet_subtitle)
.isShown();
});
onView(withId(R.id.account_picker_bottom_sheet_subtitle)).check(matches(isDisplayed()));
onView(withId(R.id.account_picker_horizontal_divider)).check(matches(not(isDisplayed())));
onView(withId(R.id.account_picker_selected_account)).check(matches(not(isDisplayed())));
onView(withId(R.id.account_picker_signin_spinner_view)).check(matches(not(isDisplayed())));
}
@Test
......
......@@ -5,6 +5,7 @@
package org.chromium.components.signin.base;
import androidx.annotation.IntDef;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.annotations.CalledByNative;
......@@ -82,8 +83,9 @@ public class GoogleServiceAuthError {
private final @State int mState;
@VisibleForTesting
@CalledByNative
private GoogleServiceAuthError(@State int state) {
public GoogleServiceAuthError(@State int state) {
mState = state;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment