Commit fd08783c authored by Nohemi Fernandez's avatar Nohemi Fernandez Committed by Chromium LUCI CQ

[iOS][MICE] Add Sync promo for signed-in users with Sync disabled.

The new promo will only be shown on the Settings page with
|kMobileIdentityConsistency| enabled. This patch does not update
interactions with promo dismissals.

Bug: 1151289
Change-Id: I5ca5701415023cca5e20cfbef6427ff16dca8888
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2565574
Commit-Queue: Nohemi Fernandez <fernandex@chromium.org>
Reviewed-by: default avatarSylvain Defresne <sdefresne@chromium.org>
Reviewed-by: default avatarJérôme Lebel <jlebel@chromium.org>
Cr-Commit-Position: refs/heads/master@{#844521}
parent b7b5cc2e
...@@ -111,6 +111,7 @@ source_set("unit_tests") { ...@@ -111,6 +111,7 @@ source_set("unit_tests") {
"//components/prefs", "//components/prefs",
"//components/signin/public/base", "//components/signin/public/base",
"//components/signin/public/identity_manager", "//components/signin/public/identity_manager",
"//components/sync/driver:test_support",
"//components/sync_preferences", "//components/sync_preferences",
"//components/sync_preferences:test_support", "//components/sync_preferences:test_support",
"//components/version_info", "//components/version_info",
...@@ -123,6 +124,7 @@ source_set("unit_tests") { ...@@ -123,6 +124,7 @@ source_set("unit_tests") {
"//ios/chrome/browser/signin", "//ios/chrome/browser/signin",
"//ios/chrome/browser/signin:test_support", "//ios/chrome/browser/signin:test_support",
"//ios/chrome/browser/sync", "//ios/chrome/browser/sync",
"//ios/chrome/browser/sync:test_support",
"//ios/chrome/browser/ui:feature_flags", "//ios/chrome/browser/ui:feature_flags",
"//ios/chrome/browser/ui/authentication/cells", "//ios/chrome/browser/ui/authentication/cells",
"//ios/chrome/browser/ui/authentication/unified_consent:unified_consent_ui", "//ios/chrome/browser/ui/authentication/unified_consent:unified_consent_ui",
......
...@@ -216,6 +216,9 @@ const CGFloat kImageViewWidthHeight = 32; ...@@ -216,6 +216,9 @@ const CGFloat kImageViewWidthHeight = 32;
case IdentityPromoViewModeSigninWithAccount: case IdentityPromoViewModeSigninWithAccount:
[self activateSigninWithAccountMode]; [self activateSigninWithAccountMode];
return; return;
case IdentityPromoViewModeSyncWithPrimaryAccount:
[self activateSyncWithPrimaryAccountMode];
return;
} }
NOTREACHED(); NOTREACHED();
} }
...@@ -238,8 +241,13 @@ const CGFloat kImageViewWidthHeight = 32; ...@@ -238,8 +241,13 @@ const CGFloat kImageViewWidthHeight = 32;
_secondaryButton.hidden = NO; _secondaryButton.hidden = NO;
} }
- (void)activateSyncWithPrimaryAccountMode {
DCHECK_EQ(_mode, IdentityPromoViewModeSyncWithPrimaryAccount);
_secondaryButton.hidden = YES;
}
- (void)setProfileImage:(UIImage*)image { - (void)setProfileImage:(UIImage*)image {
DCHECK_EQ(IdentityPromoViewModeSigninWithAccount, _mode); DCHECK_NE(_mode, IdentityPromoViewModeNoAccounts);
self.imageView.image = CircularImageFromImage(image, kProfileImageFixedSize); self.imageView.image = CircularImageFromImage(image, kProfileImageFixedSize);
} }
...@@ -268,6 +276,9 @@ const CGFloat kImageViewWidthHeight = 32; ...@@ -268,6 +276,9 @@ const CGFloat kImageViewWidthHeight = 32;
case IdentityPromoViewModeSigninWithAccount: case IdentityPromoViewModeSigninWithAccount:
[_delegate signinPromoViewDidTapSigninWithDefaultAccount:self]; [_delegate signinPromoViewDidTapSigninWithDefaultAccount:self];
break; break;
case IdentityPromoViewModeSyncWithPrimaryAccount:
[_delegate signinPromoViewDidTapSyncWithDefaultAccount:self];
break;
} }
} }
......
...@@ -64,6 +64,9 @@ using l10n_util::GetNSStringF; ...@@ -64,6 +64,9 @@ using l10n_util::GetNSStringF;
signinPromoView.closeButton.hidden = !self.hasCloseButton; signinPromoView.closeButton.hidden = !self.hasCloseButton;
signinPromoView.mode = self.identityPromoViewMode; signinPromoView.mode = self.identityPromoViewMode;
NSString* name =
self.userFullName.length ? self.userFullName : self.userEmail;
base::string16 name16 = SysNSStringToUTF16(name);
switch (self.identityPromoViewMode) { switch (self.identityPromoViewMode) {
case IdentityPromoViewModeNoAccounts: { case IdentityPromoViewModeNoAccounts: {
NSString* signInString = NSString* signInString =
...@@ -71,12 +74,9 @@ using l10n_util::GetNSStringF; ...@@ -71,12 +74,9 @@ using l10n_util::GetNSStringF;
signinPromoView.accessibilityLabel = signInString; signinPromoView.accessibilityLabel = signInString;
[signinPromoView.primaryButton setTitle:signInString [signinPromoView.primaryButton setTitle:signInString
forState:UIControlStateNormal]; forState:UIControlStateNormal];
break; return;
} }
case IdentityPromoViewModeSigninWithAccount: { case IdentityPromoViewModeSigninWithAccount: {
NSString* name =
self.userFullName.length ? self.userFullName : self.userEmail;
base::string16 name16 = SysNSStringToUTF16(name);
[signinPromoView.primaryButton [signinPromoView.primaryButton
setTitle:GetNSStringF(IDS_IOS_SIGNIN_PROMO_CONTINUE_AS, name16) setTitle:GetNSStringF(IDS_IOS_SIGNIN_PROMO_CONTINUE_AS, name16)
forState:UIControlStateNormal]; forState:UIControlStateNormal];
...@@ -85,6 +85,19 @@ using l10n_util::GetNSStringF; ...@@ -85,6 +85,19 @@ using l10n_util::GetNSStringF;
[signinPromoView.secondaryButton [signinPromoView.secondaryButton
setTitle:GetNSString(IDS_IOS_SIGNIN_PROMO_CHANGE_ACCOUNT) setTitle:GetNSString(IDS_IOS_SIGNIN_PROMO_CHANGE_ACCOUNT)
forState:UIControlStateNormal]; forState:UIControlStateNormal];
break;
}
case IdentityPromoViewModeSyncWithPrimaryAccount: {
[signinPromoView.primaryButton
setTitle:GetNSString(IDS_IOS_TAB_SWITCHER_ENABLE_SYNC_BUTTON)
forState:UIControlStateNormal];
signinPromoView.accessibilityLabel =
GetNSStringF(IDS_IOS_SIGNIN_PROMO_ACCESSIBILITY_LABEL, name16);
break;
}
}
DCHECK_NE(self.identityPromoViewMode, IdentityPromoViewModeNoAccounts);
UIImage* image = self.userImage; UIImage* image = self.userImage;
if (!image) { if (!image) {
image = ios::GetChromeBrowserProvider() image = ios::GetChromeBrowserProvider()
...@@ -92,9 +105,6 @@ using l10n_util::GetNSStringF; ...@@ -92,9 +105,6 @@ using l10n_util::GetNSStringF;
->GetDefaultAvatar(); ->GetDefaultAvatar();
} }
[signinPromoView setProfileImage:image]; [signinPromoView setProfileImage:image];
break;
}
}
} }
@end @end
...@@ -13,6 +13,8 @@ typedef NS_ENUM(NSInteger, IdentityPromoViewMode) { ...@@ -13,6 +13,8 @@ typedef NS_ENUM(NSInteger, IdentityPromoViewMode) {
// At least one identity is available on the device and the user can sign in // At least one identity is available on the device and the user can sign in
// without entering their credentials. // without entering their credentials.
IdentityPromoViewModeSigninWithAccount, IdentityPromoViewModeSigninWithAccount,
// The user is signed in to Chrome and can enable Sync on the primary account.
IdentityPromoViewModeSyncWithPrimaryAccount,
}; };
extern NSString* const kSigninPromoViewId; extern NSString* const kSigninPromoViewId;
......
...@@ -11,18 +11,22 @@ ...@@ -11,18 +11,22 @@
@protocol SigninPromoViewDelegate <NSObject> @protocol SigninPromoViewDelegate <NSObject>
// Called by SigninPromoView when the user taps the primary button in cold state // Called by SigninPromoView when the user taps the primary button with no
// mode. // identities on the device.
- (void)signinPromoViewDidTapSigninWithNewAccount:(SigninPromoView*)view; - (void)signinPromoViewDidTapSigninWithNewAccount:(SigninPromoView*)view;
// Called by SigninPromoView when the user taps the primary button in warm state // Called by SigninPromoView when the user taps the primary button with one
// mode. // or more identities on the device.
- (void)signinPromoViewDidTapSigninWithDefaultAccount:(SigninPromoView*)view; - (void)signinPromoViewDidTapSigninWithDefaultAccount:(SigninPromoView*)view;
// Called by SigninPromoView when the user taps the secondary button in warm // Called by SigninPromoView when the user taps the secondary button with one
// state mode. // or more identities on the device.
- (void)signinPromoViewDidTapSigninWithOtherAccount:(SigninPromoView*)view; - (void)signinPromoViewDidTapSigninWithOtherAccount:(SigninPromoView*)view;
// Called by SigninPromoView when the signed-in user taps the primary button
// to enable syncing with the default account.
- (void)signinPromoViewDidTapSyncWithDefaultAccount:(SigninPromoView*)view;
// Called by SigninPromoView when the user taps the close button. // Called by SigninPromoView when the user taps the close button.
- (void)signinPromoViewCloseButtonWasTapped:(SigninPromoView*)view; - (void)signinPromoViewCloseButtonWasTapped:(SigninPromoView*)view;
......
...@@ -34,6 +34,13 @@ TEST_F(SigninPromoViewTest, ChromiumLogoImage) { ...@@ -34,6 +34,13 @@ TEST_F(SigninPromoViewTest, ChromiumLogoImage) {
// The image should be different than the one set, since a circular background // The image should be different than the one set, since a circular background
// should have been added. // should have been added.
EXPECT_NE(customImage, view.imageView.image); EXPECT_NE(customImage, view.imageView.image);
view.mode = IdentityPromoViewModeSyncWithPrimaryAccount;
EXPECT_NE(nil, view.imageView.image);
// The image should has been changed from the logo.
EXPECT_NE(chromiumLogo, view.imageView.image);
// The image should be different than the one set, since a circular background
// should have been added.
EXPECT_NE(customImage, view.imageView.image);
} }
TEST_F(SigninPromoViewTest, SecondaryButtonVisibility) { TEST_F(SigninPromoViewTest, SecondaryButtonVisibility) {
...@@ -45,4 +52,6 @@ TEST_F(SigninPromoViewTest, SecondaryButtonVisibility) { ...@@ -45,4 +52,6 @@ TEST_F(SigninPromoViewTest, SecondaryButtonVisibility) {
EXPECT_TRUE(view.secondaryButton.hidden); EXPECT_TRUE(view.secondaryButton.hidden);
view.mode = IdentityPromoViewModeSigninWithAccount; view.mode = IdentityPromoViewModeSigninWithAccount;
EXPECT_FALSE(view.secondaryButton.hidden); EXPECT_FALSE(view.secondaryButton.hidden);
view.mode = IdentityPromoViewModeSyncWithPrimaryAccount;
EXPECT_TRUE(view.secondaryButton.hidden);
} }
...@@ -32,6 +32,10 @@ using chrome_test_util::WebStateScrollViewMatcher; ...@@ -32,6 +32,10 @@ using chrome_test_util::WebStateScrollViewMatcher;
// Sign-in interaction tests that work with |kMobileIdentityConsistency| // Sign-in interaction tests that work with |kMobileIdentityConsistency|
// enabled. // enabled.
@interface SigninCoordinatorMICETestCase : ChromeTestCase @interface SigninCoordinatorMICETestCase : ChromeTestCase
// Signs in to the primary user account and disables Sync.
- (void)primaryAccountSignInWithSyncDisabled;
@end @end
@implementation SigninCoordinatorMICETestCase @implementation SigninCoordinatorMICETestCase
...@@ -50,6 +54,20 @@ using chrome_test_util::WebStateScrollViewMatcher; ...@@ -50,6 +54,20 @@ using chrome_test_util::WebStateScrollViewMatcher;
[ChromeEarlGrey clearBrowsingHistory]; [ChromeEarlGrey clearBrowsingHistory];
} }
// Simulates an interrupted sign-in flow in order to emulate signing in a
// default account with the Sync feature turned off.
- (void)primaryAccountSignInWithSyncDisabled {
[ChromeEarlGreyUI openSettingsMenu];
[ChromeEarlGreyUI tapSettingsMenuButton:PrimarySignInButton()];
// Select advanced Sync Settings link.
[SigninEarlGreyUI tapSettingsLink];
[ChromeEarlGreyUI waitForAppToIdle];
// Open new tab to cancel sign-in.
[ChromeEarlGrey simulateExternalAppURLOpening];
}
// Tests that opening the sign-in screen from the Settings and signing in works // Tests that opening the sign-in screen from the Settings and signing in works
// correctly when there is already an identity on the device. // correctly when there is already an identity on the device.
- (void)testSignInFromSettingsMenu { - (void)testSignInFromSettingsMenu {
...@@ -78,15 +96,8 @@ using chrome_test_util::WebStateScrollViewMatcher; ...@@ -78,15 +96,8 @@ using chrome_test_util::WebStateScrollViewMatcher;
- (void)testSignInFromSyncOffLink { - (void)testSignInFromSyncOffLink {
FakeChromeIdentity* fakeIdentity = [SigninEarlGrey fakeIdentity1]; FakeChromeIdentity* fakeIdentity = [SigninEarlGrey fakeIdentity1];
[SigninEarlGrey addFakeIdentity:fakeIdentity]; [SigninEarlGrey addFakeIdentity:fakeIdentity];
[ChromeEarlGreyUI openSettingsMenu];
[ChromeEarlGreyUI tapSettingsMenuButton:PrimarySignInButton()];
// Select advanced Sync Settings link. [self primaryAccountSignInWithSyncDisabled];
[SigninEarlGreyUI tapSettingsLink];
[ChromeEarlGreyUI waitForAppToIdle];
// Open new tab to cancel sign-in.
[ChromeEarlGrey simulateExternalAppURLOpening];
[ChromeEarlGreyUI openSettingsMenu]; [ChromeEarlGreyUI openSettingsMenu];
// Check Sync Off label is visible and user is signed in. // Check Sync Off label is visible and user is signed in.
...@@ -116,4 +127,87 @@ using chrome_test_util::WebStateScrollViewMatcher; ...@@ -116,4 +127,87 @@ using chrome_test_util::WebStateScrollViewMatcher;
[ChromeEarlGreyUI waitForToolbarVisible:YES]; [ChromeEarlGreyUI waitForToolbarVisible:YES];
} }
// Tests that the sign-in promo for no identities is displayed in Settings when
// the user is signed out and has not added any identities to the device.
- (void)testSigninPromoWithNoIdentitiesOnDevice {
[ChromeEarlGreyUI openSettingsMenu];
[SigninEarlGrey verifySignedOut];
[SigninEarlGreyUI
verifySigninPromoVisibleWithMode:IdentityPromoViewModeNoAccounts];
}
// Tests that the sign-in promo with user name is displayed in Settings when the
// user is signed out.
- (void)testSigninPromoWhenSignedOut {
// Add identity to the device.
FakeChromeIdentity* fakeIdentity = [SigninEarlGrey fakeIdentity1];
[SigninEarlGrey addFakeIdentity:fakeIdentity];
[ChromeEarlGreyUI openSettingsMenu];
[SigninEarlGrey verifySignedOut];
[SigninEarlGreyUI
verifySigninPromoVisibleWithMode:IdentityPromoViewModeSigninWithAccount];
}
// Tests that the sign-in promo is removed from Settings when the user
// is signed out and has closed the sign-in promo with user name.
- (void)testSigninPromoClosedWhenSignedOut {
// Add identity to the device.
FakeChromeIdentity* fakeIdentity = [SigninEarlGrey fakeIdentity1];
[SigninEarlGrey addFakeIdentity:fakeIdentity];
[ChromeEarlGreyUI openSettingsMenu];
[SigninEarlGreyUI
verifySigninPromoVisibleWithMode:IdentityPromoViewModeSigninWithAccount
closeButton:YES];
[[EarlGrey
selectElementWithMatcher:grey_allOf(grey_accessibilityID(
kSigninPromoCloseButtonId),
grey_sufficientlyVisible(), nil)]
performAction:grey_tap()];
[SigninEarlGrey verifySignedOut];
[SigninEarlGreyUI verifySigninPromoNotVisible];
}
// Tests that the sign-in promo for Sync is displayed when the user is signed in
// with Sync off.
- (void)testSigninPromoWhenSyncOff {
// Add identity to the device.
FakeChromeIdentity* fakeIdentity = [SigninEarlGrey fakeIdentity1];
[SigninEarlGrey addFakeIdentity:fakeIdentity];
[self primaryAccountSignInWithSyncDisabled];
[ChromeEarlGreyUI openSettingsMenu];
[SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity];
[SigninEarlGreyUI verifySigninPromoVisibleWithMode:
IdentityPromoViewModeSyncWithPrimaryAccount];
}
// Tests that no sign-in promo for Sync is displayed when the user is signed in
// with Sync off and has closed the sign-in promo for Sync.
- (void)testSigninPromoClosedWhenSyncOff {
// Add identity to the device.
FakeChromeIdentity* fakeIdentity = [SigninEarlGrey fakeIdentity1];
[SigninEarlGrey addFakeIdentity:fakeIdentity];
[self primaryAccountSignInWithSyncDisabled];
[ChromeEarlGreyUI openSettingsMenu];
[SigninEarlGreyUI verifySigninPromoVisibleWithMode:
IdentityPromoViewModeSyncWithPrimaryAccount];
// Tap on dismiss button.
[[EarlGrey
selectElementWithMatcher:grey_allOf(grey_accessibilityID(
kSigninPromoCloseButtonId),
grey_sufficientlyVisible(), nil)]
performAction:grey_tap()];
[SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity];
[SigninEarlGreyUI verifySigninPromoNotVisible];
}
@end @end
...@@ -168,6 +168,7 @@ using chrome_test_util::SignOutAccountsButton; ...@@ -168,6 +168,7 @@ using chrome_test_util::SignOutAccountsButton;
assertWithMatcher:grey_notNil()]; assertWithMatcher:grey_notNil()];
switch (mode) { switch (mode) {
case IdentityPromoViewModeNoAccounts: case IdentityPromoViewModeNoAccounts:
case IdentityPromoViewModeSyncWithPrimaryAccount:
[[EarlGrey [[EarlGrey
selectElementWithMatcher:grey_allOf(SecondarySignInButton(), selectElementWithMatcher:grey_allOf(SecondarySignInButton(),
grey_sufficientlyVisible(), nil)] grey_sufficientlyVisible(), nil)]
......
...@@ -435,8 +435,14 @@ const char* AlreadySeenSigninViewPreferenceKey( ...@@ -435,8 +435,14 @@ const char* AlreadySeenSigninViewPreferenceKey(
BOOL hasCloseButton = BOOL hasCloseButton =
AlreadySeenSigninViewPreferenceKey(self.accessPoint) != nullptr; AlreadySeenSigninViewPreferenceKey(self.accessPoint) != nullptr;
if (_defaultIdentity) { if (_defaultIdentity) {
AuthenticationService* authService =
AuthenticationServiceFactory::GetForBrowserState(_browserState);
IdentityPromoViewMode viewMode =
authService->IsAuthenticated()
? IdentityPromoViewModeSyncWithPrimaryAccount
: IdentityPromoViewModeSigninWithAccount;
return [[SigninPromoViewConfigurator alloc] return [[SigninPromoViewConfigurator alloc]
initWithIdentityPromoViewMode:IdentityPromoViewModeSigninWithAccount initWithIdentityPromoViewMode:viewMode
userEmail:_defaultIdentity.userEmail userEmail:_defaultIdentity.userEmail
userFullName:_defaultIdentity.userFullName userFullName:_defaultIdentity.userFullName
userImage:self.identityAvatar userImage:self.identityAvatar
...@@ -676,6 +682,17 @@ const char* AlreadySeenSigninViewPreferenceKey( ...@@ -676,6 +682,17 @@ const char* AlreadySeenSigninViewPreferenceKey(
[self showSigninWithIdentity:_defaultIdentity promoAction:promo_action]; [self showSigninWithIdentity:_defaultIdentity promoAction:promo_action];
} }
- (void)signinPromoViewDidTapSyncWithDefaultAccount:
(SigninPromoView*)signinPromoView {
DCHECK(_defaultIdentity);
DCHECK(self.signinPromoViewVisible);
DCHECK(!self.invalidClosedOrNeverVisible);
// TODO(crbug.com/1166232): Record Sync impressions.
[self showSigninWithIdentity:_defaultIdentity
promoAction:signin_metrics::PromoAction::
PROMO_ACTION_WITH_DEFAULT];
}
- (void)signinPromoViewDidTapSigninWithOtherAccount: - (void)signinPromoViewDidTapSigninWithOtherAccount:
(SigninPromoView*)signinPromoView { (SigninPromoView*)signinPromoView {
DCHECK(_defaultIdentity); DCHECK(_defaultIdentity);
......
...@@ -12,12 +12,18 @@ ...@@ -12,12 +12,18 @@
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "components/signin/public/base/signin_metrics.h" #include "components/signin/public/base/signin_metrics.h"
#import "components/signin/public/base/signin_pref_names.h" #import "components/signin/public/base/signin_pref_names.h"
#import "components/sync/driver/mock_sync_service.h"
#import "components/sync_preferences/pref_service_mock_factory.h" #import "components/sync_preferences/pref_service_mock_factory.h"
#import "components/sync_preferences/pref_service_syncable.h" #import "components/sync_preferences/pref_service_syncable.h"
#import "ios/chrome/browser/browser_state/test_chrome_browser_state.h" #import "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
#import "ios/chrome/browser/chrome_switches.h" #import "ios/chrome/browser/chrome_switches.h"
#import "ios/chrome/browser/prefs/browser_prefs.h" #import "ios/chrome/browser/prefs/browser_prefs.h"
#import "ios/chrome/browser/signin/authentication_service_factory.h"
#import "ios/chrome/browser/signin/authentication_service_fake.h"
#include "ios/chrome/browser/signin/chrome_identity_service_observer_bridge.h" #include "ios/chrome/browser/signin/chrome_identity_service_observer_bridge.h"
#import "ios/chrome/browser/sync/profile_sync_service_factory.h"
#import "ios/chrome/browser/sync/sync_setup_service_factory.h"
#import "ios/chrome/browser/sync/sync_setup_service_mock.h"
#import "ios/chrome/browser/ui/authentication/cells/signin_promo_view.h" #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view.h"
#import "ios/chrome/browser/ui/authentication/cells/signin_promo_view_configurator.h" #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view_configurator.h"
#import "ios/chrome/browser/ui/authentication/cells/signin_promo_view_constants.h" #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view_constants.h"
...@@ -47,12 +53,27 @@ using user_prefs::PrefRegistrySyncable; ...@@ -47,12 +53,27 @@ using user_prefs::PrefRegistrySyncable;
using web::WebTaskEnvironment; using web::WebTaskEnvironment;
namespace { namespace {
std::unique_ptr<KeyedService> BuildMockSyncService(web::BrowserState* context) {
return std::make_unique<syncer::MockSyncService>();
}
class SigninPromoViewMediatorTest : public PlatformTest { class SigninPromoViewMediatorTest : public PlatformTest {
protected: protected:
void SetUp() override { void SetUp() override {
user_full_name_ = @"John Doe"; user_full_name_ = @"John Doe";
close_button_hidden_ = YES; close_button_hidden_ = YES;
TestChromeBrowserState::Builder builder;
builder.AddTestingFactory(ProfileSyncServiceFactory::GetInstance(),
base::BindRepeating(&BuildMockSyncService));
builder.AddTestingFactory(
SyncSetupServiceFactory::GetInstance(),
base::BindRepeating(&SyncSetupServiceMock::CreateKeyedService));
builder.AddTestingFactory(
AuthenticationServiceFactory::GetInstance(),
base::BindRepeating(
&AuthenticationServiceFake::CreateAuthenticationService));
chrome_browser_state_ = builder.Build();
} }
void TearDown() override { void TearDown() override {
...@@ -73,8 +94,8 @@ class SigninPromoViewMediatorTest : public PlatformTest { ...@@ -73,8 +94,8 @@ class SigninPromoViewMediatorTest : public PlatformTest {
void CreateMediator(signin_metrics::AccessPoint accessPoint) { void CreateMediator(signin_metrics::AccessPoint accessPoint) {
consumer_ = OCMStrictProtocolMock(@protocol(SigninPromoViewConsumer)); consumer_ = OCMStrictProtocolMock(@protocol(SigninPromoViewConsumer));
mediator_ = mediator_ = [[SigninPromoViewMediator alloc]
[[SigninPromoViewMediator alloc] initWithBrowserState:nil initWithBrowserState:chrome_browser_state_.get()
accessPoint:accessPoint accessPoint:accessPoint
presenter:nil]; presenter:nil];
mediator_.consumer = consumer_; mediator_.consumer = consumer_;
...@@ -209,6 +230,7 @@ class SigninPromoViewMediatorTest : public PlatformTest { ...@@ -209,6 +230,7 @@ class SigninPromoViewMediatorTest : public PlatformTest {
// Task environment. // Task environment.
WebTaskEnvironment task_environment_; WebTaskEnvironment task_environment_;
std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
// Mediator used for the tests. // Mediator used for the tests.
SigninPromoViewMediator* mediator_; SigninPromoViewMediator* mediator_;
......
...@@ -115,10 +115,10 @@ using chrome_test_util::SecondarySignInButton; ...@@ -115,10 +115,10 @@ using chrome_test_util::SecondarySignInButton;
[BookmarkEarlGrey verifyPromoAlreadySeen:YES]; [BookmarkEarlGrey verifyPromoAlreadySeen:YES];
} }
// Tests the tapping on the primary button of sign-in promo view in a cold // Tests the tapping on the primary button of sign-in promo view with no
// state makes the sign-in sheet appear, and the promo still appears after // identities on device makes the sign-in sheet appear, and the promo still
// dismissing the sheet. // appears after dismissing the sheet.
- (void)testSignInPromoWithColdStateUsingPrimaryButton { - (void)testSignInPromoWithNoIdentitiesUsingPrimaryButton {
[BookmarkEarlGreyUI openBookmarks]; [BookmarkEarlGreyUI openBookmarks];
// Check that sign-in promo view are visible. // Check that sign-in promo view are visible.
...@@ -142,10 +142,10 @@ using chrome_test_util::SecondarySignInButton; ...@@ -142,10 +142,10 @@ using chrome_test_util::SecondarySignInButton;
verifySigninPromoVisibleWithMode:IdentityPromoViewModeNoAccounts]; verifySigninPromoVisibleWithMode:IdentityPromoViewModeNoAccounts];
} }
// Tests the tapping on the primary button of sign-in promo view in a warm // Tests the tapping on the primary button of sign-in promo view with identities
// state makes the confirmaiton sheet appear, and the promo still appears after // on device makes the confirmaiton sheet appear, and the promo still appears
// dismissing the sheet. // after dismissing the sheet.
- (void)testSignInPromoWithWarmStateUsingPrimaryButton { - (void)testSignInPromoWithIdentitiesUsingPrimaryButton {
[BookmarkEarlGrey setupStandardBookmarks]; [BookmarkEarlGrey setupStandardBookmarks];
[BookmarkEarlGreyUI openBookmarks]; [BookmarkEarlGreyUI openBookmarks];
...@@ -175,10 +175,10 @@ using chrome_test_util::SecondarySignInButton; ...@@ -175,10 +175,10 @@ using chrome_test_util::SecondarySignInButton;
[BookmarkEarlGrey verifyPromoAlreadySeen:NO]; [BookmarkEarlGrey verifyPromoAlreadySeen:NO];
} }
// Tests the tapping on the secondary button of sign-in promo view in a warm // Tests the tapping on the secondary button of sign-in promo view with
// state makes the sign-in sheet appear, and the promo still appears after // identities on device makes the sign-in sheet appear, and the promo still
// dismissing the sheet. // appears after dismissing the sheet.
- (void)testSignInPromoWithWarmStateUsingSecondaryButton { - (void)testSignInPromoWithIdentitiesUsingSecondaryButton {
[BookmarkEarlGrey setupStandardBookmarks]; [BookmarkEarlGrey setupStandardBookmarks];
[BookmarkEarlGreyUI openBookmarks]; [BookmarkEarlGreyUI openBookmarks];
......
...@@ -290,7 +290,7 @@ GURL TestPageURL() { ...@@ -290,7 +290,7 @@ GURL TestPageURL() {
} }
} }
// Tests that the Cold Mode Signin promo is visible in the Other Devices section // Tests that the Signin promo is visible in the Other Devices section
// (and with illustrated-empty-states enabled, there is the illustrated cell) // (and with illustrated-empty-states enabled, there is the illustrated cell)
- (void)testOtherDevicesDefaultEmptyState { - (void)testOtherDevicesDefaultEmptyState {
OpenRecentTabsPanel(); OpenRecentTabsPanel();
......
...@@ -392,63 +392,9 @@ SyncState GetSyncStateFromBrowserState(ChromeBrowserState* browserState) { ...@@ -392,63 +392,9 @@ SyncState GetSyncStateFromBrowserState(ChromeBrowserState* browserState) {
TableViewModel<TableViewItem*>* model = self.tableViewModel; TableViewModel<TableViewItem*>* model = self.tableViewModel;
AuthenticationService* authService = [self addPromoToIdentitySection];
AuthenticationServiceFactory::GetForBrowserState(_browserState); [self addAccountProfileToIdentitySection];
// If sign-in is disabled by policy, replace the sign-in / account section [self addSyncAndGoogleServicesToIdentitySection];
// with an info button view item.
if (!signin::IsSigninAllowed(_browserState->GetPrefs())) {
[model addSectionWithIdentifier:SettingsSectionIdentifierSignIn];
[model addItem:[self signinDisabledTextItem]
toSectionWithIdentifier:SettingsSectionIdentifierSignIn];
} else if (!authService->IsAuthenticated()) {
// Sign in section
[model addSectionWithIdentifier:SettingsSectionIdentifierSignIn];
if ([SigninPromoViewMediator
shouldDisplaySigninPromoViewWithAccessPoint:
signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS
browserState:_browserState]) {
if (!_signinPromoViewMediator) {
_signinPromoViewMediator = [[SigninPromoViewMediator alloc]
initWithBrowserState:_browserState
accessPoint:signin_metrics::AccessPoint::
ACCESS_POINT_SETTINGS
presenter:self /* id<SigninPresenter> */];
_signinPromoViewMediator.consumer = self;
}
} else {
[_signinPromoViewMediator signinPromoViewIsRemoved];
_signinPromoViewMediator = nil;
}
[model addItem:[self signInTextItem]
toSectionWithIdentifier:SettingsSectionIdentifierSignIn];
} else {
// Account section
[model addSectionWithIdentifier:SettingsSectionIdentifierAccount];
_hasRecordedSigninImpression = NO;
[_signinPromoViewMediator signinPromoViewIsRemoved];
_signinPromoViewMediator = nil;
[model addItem:[self accountCellItem]
toSectionWithIdentifier:SettingsSectionIdentifierAccount];
}
if (![model
hasSectionForSectionIdentifier:SettingsSectionIdentifierAccount]) {
// Add the Account section for the Sync & Google services cell, if the user
// is signed-out.
[model addSectionWithIdentifier:SettingsSectionIdentifierAccount];
}
// Adds experimental Google Services item separate from Sync.
if (base::FeatureList::IsEnabled(signin::kMobileIdentityConsistency)) {
if (authService->IsAuthenticated()) {
[model addItem:[self googleSyncDetailItem]
toSectionWithIdentifier:SettingsSectionIdentifierAccount];
}
[model addItem:[self googleServicesCellItem]
toSectionWithIdentifier:SettingsSectionIdentifierAccount];
} else {
[model addItem:[self syncAndGoogleServicesCellItem]
toSectionWithIdentifier:SettingsSectionIdentifierAccount];
}
// Defaults section. // Defaults section.
if (@available(iOS 14, *)) { if (@available(iOS 14, *)) {
...@@ -531,6 +477,138 @@ SyncState GetSyncStateFromBrowserState(ChromeBrowserState* browserState) { ...@@ -531,6 +477,138 @@ SyncState GetSyncStateFromBrowserState(ChromeBrowserState* browserState) {
#endif // BUILDFLAG(CHROMIUM_BRANDING) && !defined(NDEBUG) #endif // BUILDFLAG(CHROMIUM_BRANDING) && !defined(NDEBUG)
} }
// Adds the identity promo to promote the sign-in or sync state.
- (void)addPromoToIdentitySection {
TableViewModel<TableViewItem*>* model = self.tableViewModel;
[model addSectionWithIdentifier:SettingsSectionIdentifierSignIn];
AuthenticationService* authService =
AuthenticationServiceFactory::GetForBrowserState(_browserState);
if ((authService->IsAuthenticated() && self.shouldDisplaySyncPromo) ||
(!authService->IsAuthenticated() && self.shouldDisplaySigninPromo)) {
if (!_signinPromoViewMediator) {
_signinPromoViewMediator = [[SigninPromoViewMediator alloc]
initWithBrowserState:_browserState
accessPoint:signin_metrics::AccessPoint::
ACCESS_POINT_SETTINGS
presenter:self /* id<SigninPresenter> */];
_signinPromoViewMediator.consumer = self;
}
TableViewSigninPromoItem* identityPromoItem =
[[TableViewSigninPromoItem alloc]
initWithType:SettingsItemTypeSigninPromo];
identityPromoItem.text =
l10n_util::GetNSString(IDS_IOS_SIGNIN_PROMO_SETTINGS_WITH_UNITY);
identityPromoItem.configurator =
[_signinPromoViewMediator createConfigurator];
identityPromoItem.delegate = _signinPromoViewMediator;
[_signinPromoViewMediator signinPromoViewIsVisible];
[model addItem:identityPromoItem
toSectionWithIdentifier:SettingsSectionIdentifierSignIn];
} else if (!authService->IsAuthenticated()) {
[_signinPromoViewMediator signinPromoViewIsRemoved];
_signinPromoViewMediator = nil;
if (!_hasRecordedSigninImpression) {
// Once the Settings are open, this button impression will at most be
// recorded once until they are closed.
signin_metrics::RecordSigninImpressionUserActionForAccessPoint(
signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS);
_hasRecordedSigninImpression = YES;
}
}
}
// Adds the account profile to the Identity section if the user is signed in and
// sign-in is not disabled by policy.
- (void)addAccountProfileToIdentitySection {
// If sign-in is disabled by policy, replace the sign-in / account section
// with an info button view item.
TableViewModel<TableViewItem*>* model = self.tableViewModel;
if (!signin::IsSigninAllowed(_browserState->GetPrefs())) {
[model addItem:[self signinDisabledTextItem]
toSectionWithIdentifier:SettingsSectionIdentifierSignIn];
return;
}
AuthenticationService* authService =
AuthenticationServiceFactory::GetForBrowserState(_browserState);
if (authService->IsAuthenticated()) {
// Account profile item.
[model addSectionWithIdentifier:SettingsSectionIdentifierAccount];
[model addItem:[self accountCellItem]
toSectionWithIdentifier:SettingsSectionIdentifierAccount];
_hasRecordedSigninImpression = NO;
} else if (!authService->IsAuthenticated() &&
!self.shouldDisplaySigninPromo) {
// Signed-out default
AccountSignInItem* signInTextItem =
[[AccountSignInItem alloc] initWithType:SettingsItemTypeSignInButton];
signInTextItem.accessibilityIdentifier = kSettingsSignInCellId;
signInTextItem.detailText =
l10n_util::GetNSString(IDS_IOS_SIGN_IN_TO_CHROME_SETTING_SUBTITLE);
[model addItem:signInTextItem
toSectionWithIdentifier:SettingsSectionIdentifierSignIn];
}
}
// Adds the Sync & Google Services options to the Identity section.
- (void)addSyncAndGoogleServicesToIdentitySection {
// Add the Account section for the Sync & Google services cell, if the
// user is signed-out.
TableViewModel<TableViewItem*>* model = self.tableViewModel;
if (![model
hasSectionForSectionIdentifier:SettingsSectionIdentifierAccount]) {
[model addSectionWithIdentifier:SettingsSectionIdentifierAccount];
}
if (base::FeatureList::IsEnabled(signin::kMobileIdentityConsistency)) {
AuthenticationService* authService =
AuthenticationServiceFactory::GetForBrowserState(_browserState);
// Sync item.
if (authService->IsAuthenticated()) {
[model addItem:[self googleSyncDetailItem]
toSectionWithIdentifier:SettingsSectionIdentifierAccount];
}
// Google Services item.
[model addItem:[self googleServicesCellItem]
toSectionWithIdentifier:SettingsSectionIdentifierAccount];
} else {
// Sync & Google Services item.
[model addItem:[self syncAndGoogleServicesCellItem]
toSectionWithIdentifier:SettingsSectionIdentifierAccount];
}
}
#pragma mark - Properties
// Returns YES if the sign-in promo has not previously been closed or seen
// too many times by a single user account (as defined in
// SigninPromoViewMediator).
- (BOOL)shouldDisplaySigninPromo {
return [SigninPromoViewMediator
shouldDisplaySigninPromoViewWithAccessPoint:signin_metrics::AccessPoint::
ACCESS_POINT_SETTINGS
browserState:_browserState];
}
// Returns YES if the Sync service is available and all promos have not been
// previously closed or seen too many times by a single user account.
- (BOOL)shouldDisplaySyncPromo {
syncer::SyncService* syncService =
ProfileSyncServiceFactory::GetForBrowserState(_browserState);
return base::FeatureList::IsEnabled(signin::kMobileIdentityConsistency) &&
// TODO(crbug.com/1166232): Replace with Sync specific metrics.
[SigninPromoViewMediator
shouldDisplaySigninPromoViewWithAccessPoint:
signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS
browserState:_browserState] &&
(!syncService->IsSyncFeatureActive() &&
syncService->GetTransportState() !=
syncer::SyncService::TransportState::INITIALIZING);
}
#pragma mark - Model Items #pragma mark - Model Items
- (TableViewItem*)signInTextItem { - (TableViewItem*)signInTextItem {
......
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