Commit ad71401e authored by Nohemi Fernandez's avatar Nohemi Fernandez Committed by Commit Bot

[iOS][MICE] Add sync error states to Sync Settings page.

Moves the Sync errors item out of Google Services into the Sync settings
page for the MICE experiment.

Bug: 1125631
Change-Id: I4f373a14e967e76d55f7d0aa7b8ed02a53c495df
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2461266
Commit-Queue: Nohemi Fernandez <fernandex@chromium.org>
Reviewed-by: default avatarJérôme Lebel <jlebel@chromium.org>
Cr-Commit-Position: refs/heads/master@{#816172}
parent 6c09107f
......@@ -28,6 +28,7 @@ source_set("google_services") {
"manage_sync_settings_table_view_controller.h",
"manage_sync_settings_table_view_controller.mm",
"manage_sync_settings_view_controller_model_delegate.h",
"sync_error_settings_command_handler.h",
]
deps = [
":constants",
......@@ -58,6 +59,7 @@ source_set("google_services") {
"//ios/chrome/browser/ui/alert_coordinator",
"//ios/chrome/browser/ui/authentication",
"//ios/chrome/browser/ui/authentication/cells",
"//ios/chrome/browser/ui/authentication/signin:signin_protected",
"//ios/chrome/browser/ui/commands",
"//ios/chrome/browser/ui/coordinators:chrome_coordinators",
"//ios/chrome/browser/ui/icons",
......
......@@ -8,15 +8,6 @@
// Protocol to communicate user actions from the mediator to its coordinator.
@protocol GoogleServicesSettingsCommandHandler <NSObject>
// Restarts the authentication flow.
- (void)restartAuthenticationFlow;
// Opens the reauth sync dialog.
- (void)openReauthDialogAsSyncIsInAuthError;
// Opens the passphrase dialog.
- (void)openPassphraseDialog;
// Presents the sign-in dialog to the user.
- (void)showSignIn;
......@@ -33,9 +24,6 @@
// TODO(crbug.com/1043080): Remove web page API once MyGoogle UI is launched.
- (void)openManageGoogleAccountWebPage;
// Opens the trusted vault reauthentication dialog.
- (void)openTrustedVaultReauth;
@end
#endif // IOS_CHROME_BROWSER_UI_SETTINGS_GOOGLE_SERVICES_GOOGLE_SERVICES_SETTINGS_COMMAND_HANDLER_H_
......@@ -28,6 +28,7 @@
#import "ios/chrome/browser/ui/settings/google_services/google_services_settings_mediator.h"
#import "ios/chrome/browser/ui/settings/google_services/google_services_settings_view_controller.h"
#import "ios/chrome/browser/ui/settings/google_services/manage_sync_settings_coordinator.h"
#import "ios/chrome/browser/ui/settings/google_services/sync_error_settings_command_handler.h"
#import "ios/chrome/browser/ui/settings/sync/sync_encryption_passphrase_table_view_controller.h"
#include "ios/chrome/browser/ui/ui_feature_flags.h"
#import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
......@@ -42,7 +43,8 @@ using signin_metrics::PromoAction;
@interface GoogleServicesSettingsCoordinator () <
GoogleServicesSettingsCommandHandler,
GoogleServicesSettingsViewControllerPresentationDelegate,
ManageSyncSettingsCoordinatorDelegate>
ManageSyncSettingsCoordinatorDelegate,
SyncErrorSettingsCommandHandler>
// Google services settings mode.
@property(nonatomic, assign, readonly) GoogleServicesSettingsMode mode;
......@@ -111,6 +113,7 @@ using signin_metrics::PromoAction;
self.mediator.identityManager = IdentityManagerFactory::GetForBrowserState(
self.browser->GetBrowserState());
self.mediator.commandHandler = self;
self.mediator.syncErrorHandler = self;
self.mediator.syncService = ProfileSyncServiceFactory::GetForBrowserState(
self.browser->GetBrowserState());
viewController.modelDelegate = self.mediator;
......@@ -170,7 +173,7 @@ using signin_metrics::PromoAction;
isEqual:self.baseNavigationController.topViewController];
}
#pragma mark - GoogleServicesSettingsCommandHandler
#pragma mark - SyncErrorSettingsCommandHandler
- (void)restartAuthenticationFlow {
ChromeIdentity* authenticatedIdentity =
......@@ -222,6 +225,20 @@ using signin_metrics::PromoAction;
[self.baseNavigationController pushViewController:controller animated:YES];
}
- (void)openTrustedVaultReauth {
id<ApplicationCommands> applicationCommands =
static_cast<id<ApplicationCommands>>(
self.browser->GetCommandDispatcher());
[applicationCommands
showTrustedVaultReauthenticationFromViewController:
self.googleServicesSettingsViewController
retrievalTrigger:
syncer::KeyRetrievalTriggerForUMA::
kSettings];
}
#pragma mark - GoogleServicesSettingsCommandHandler
- (void)showSignIn {
__weak __typeof(self) weakSelf = self;
DCHECK(self.handler);
......@@ -287,18 +304,6 @@ using signin_metrics::PromoAction;
[handler closeSettingsUIAndOpenURL:command];
}
- (void)openTrustedVaultReauth {
id<ApplicationCommands> applicationCommands =
static_cast<id<ApplicationCommands>>(
self.browser->GetCommandDispatcher());
[applicationCommands
showTrustedVaultReauthenticationFromViewController:
self.googleServicesSettingsViewController
retrievalTrigger:
syncer::KeyRetrievalTriggerForUMA::
kSettings];
}
#pragma mark - GoogleServicesSettingsViewControllerPresentationDelegate
- (void)googleServicesSettingsViewControllerDidRemove:
......
......@@ -17,6 +17,7 @@ class AuthenticationService;
@protocol GoogleServicesSettingsCommandHandler;
@class GoogleServicesSettingsViewController;
class PrefService;
@protocol SyncErrorSettingsCommandHandler;
class SyncSetupService;
namespace syncer {
......@@ -41,6 +42,8 @@ class IdentityManager;
// Command handler.
@property(nonatomic, weak) id<GoogleServicesSettingsCommandHandler>
commandHandler;
// Sync error handler.
@property(nonatomic, weak) id<SyncErrorSettingsCommandHandler> syncErrorHandler;
// Sync service.
@property(nonatomic, assign) syncer::SyncService* syncService;
// Identity manager;
......
......@@ -30,6 +30,7 @@
#import "ios/chrome/browser/ui/settings/cells/sync_switch_item.h"
#import "ios/chrome/browser/ui/settings/google_services/google_services_settings_command_handler.h"
#import "ios/chrome/browser/ui/settings/google_services/google_services_settings_constants.h"
#import "ios/chrome/browser/ui/settings/google_services/sync_error_settings_command_handler.h"
#import "ios/chrome/browser/ui/settings/sync/utils/sync_util.h"
#import "ios/chrome/browser/ui/settings/utils/observable_boolean.h"
#import "ios/chrome/browser/ui/settings/utils/pref_backed_boolean.h"
......@@ -323,6 +324,11 @@ NSString* kGoogleServicesSyncErrorImage = @"google_services_sync_error";
// Updates the sync section. If |notifyConsumer| is YES, the consumer is
// notified about model changes.
- (void)updateSyncSection:(BOOL)notifyConsumer {
if (base::FeatureList::IsEnabled(signin::kMobileIdentityConsistency)) {
// Chrome adds the sync section within "Manage Your Settings" for the MICE
// experiment.
return;
}
BOOL needsAccountSigninItemUpdate = [self updateAccountSignInItem];
BOOL needsSyncErrorItemsUpdate = [self updateSyncErrorItems];
BOOL needsSyncChromeDataItemUpdate = [self updateSyncChromeDataItem];
......@@ -596,12 +602,7 @@ NSString* kGoogleServicesSyncErrorImage = @"google_services_sync_error";
}
- (BOOL)shouldDisplaySync {
BOOL experimentEnabled =
base::FeatureList::IsEnabled(signin::kMobileIdentityConsistency);
BOOL firstSetupWithExperiment =
!self.syncSetupService->IsFirstSetupComplete() && experimentEnabled;
return (firstSetupWithExperiment || !experimentEnabled) &&
self.isAuthenticated && !self.isSyncDisabledByAdministrator;
return self.isAuthenticated && !self.isSyncDisabledByAdministrator;
}
- (ItemArray)nonPersonalizedItems {
......@@ -815,7 +816,11 @@ NSString* kGoogleServicesSyncErrorImage = @"google_services_sync_error";
(GoogleServicesSettingsViewController*)controller {
DCHECK_EQ(self.consumer, controller);
[self loadIdentitySection];
[self loadSyncSection];
// For the MICE experiment Chrome will display the Sync section within "Manage
// Sync Settings".
if (!base::FeatureList::IsEnabled(signin::kMobileIdentityConsistency)) {
[self loadSyncSection];
}
[self loadNonPersonalizedSection];
_identityManagerObserverBridge.reset(
new signin::IdentityManagerObserverBridge(self.identityManager, self));
......@@ -905,16 +910,16 @@ NSString* kGoogleServicesSyncErrorImage = @"google_services_sync_error";
[self.commandHandler showSignIn];
break;
case RestartAuthenticationFlowErrorItemType:
[self.commandHandler restartAuthenticationFlow];
[self.syncErrorHandler restartAuthenticationFlow];
break;
case ReauthDialogAsSyncIsInAuthErrorItemType:
[self.commandHandler openReauthDialogAsSyncIsInAuthError];
[self.syncErrorHandler openReauthDialogAsSyncIsInAuthError];
break;
case ShowPassphraseDialogErrorItemType:
[self.commandHandler openPassphraseDialog];
[self.syncErrorHandler openPassphraseDialog];
break;
case SyncNeedsTrustedVaultKeyErrorItemType:
[self.commandHandler openTrustedVaultReauth];
[self.syncErrorHandler openTrustedVaultReauth];
break;
case ManageSyncItemType:
[self.commandHandler openManageSyncSettings];
......
......@@ -10,12 +10,9 @@
// Protocol to communicate user actions from the mediator to its coordinator.
@protocol ManageSyncSettingsCommandHandler <NSObject>
// Opens the passphrase dialog.
- (void)openPassphraseDialog;
// Opens the trusted vault reauthentication dialog.
- (void)openTrustedVaultReauth;
// Opens the "Web & App Activity" dialog.
- (void)openWebAppActivityDialog;
// Opens the "Data from Chrome sync" web page.
- (void)openDataFromChromeSyncWebPage;
......
......@@ -20,6 +20,9 @@
// yet.
- (void)reloadItem:(TableViewItem*)item;
// Reloads |sections|. Does nothing if the model is not loaded yet.
- (void)reloadSections:(NSIndexSet*)sections;
@end
#endif // IOS_CHROME_BROWSER_UI_SETTINGS_GOOGLE_SERVICES_MANAGE_SYNC_SETTINGS_CONSUMER_H_
......@@ -20,13 +20,16 @@
#include "ios/chrome/browser/sync/profile_sync_service_factory.h"
#include "ios/chrome/browser/sync/sync_observer_bridge.h"
#include "ios/chrome/browser/sync/sync_setup_service_factory.h"
#import "ios/chrome/browser/ui/authentication/authentication_flow.h"
#import "ios/chrome/browser/ui/commands/application_commands.h"
#import "ios/chrome/browser/ui/commands/browsing_data_commands.h"
#import "ios/chrome/browser/ui/commands/command_dispatcher.h"
#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
#import "ios/chrome/browser/ui/icons/chrome_icon.h"
#import "ios/chrome/browser/ui/settings/google_services/manage_sync_settings_command_handler.h"
#import "ios/chrome/browser/ui/settings/google_services/manage_sync_settings_mediator.h"
#import "ios/chrome/browser/ui/settings/google_services/manage_sync_settings_table_view_controller.h"
#import "ios/chrome/browser/ui/settings/google_services/sync_error_settings_command_handler.h"
#import "ios/chrome/browser/ui/settings/sync/sync_encryption_passphrase_table_view_controller.h"
#import "ios/chrome/browser/ui/settings/sync/sync_encryption_table_view_controller.h"
#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
......@@ -38,9 +41,13 @@
#error "This file requires ARC support."
#endif
using signin_metrics::AccessPoint;
using signin_metrics::PromoAction;
@interface ManageSyncSettingsCoordinator () <
ChromeIdentityBrowserOpener,
ManageSyncSettingsCommandHandler,
SyncErrorSettingsCommandHandler,
ManageSyncSettingsTableViewControllerPresentationDelegate,
SyncObserverModelBridge> {
// Sync observer.
......@@ -54,9 +61,13 @@
@property(nonatomic, strong) ManageSyncSettingsMediator* mediator;
// Sync service.
@property(nonatomic, assign, readonly) syncer::SyncService* syncService;
// Authentication service.
@property(nonatomic, assign, readonly) AuthenticationService* authService;
// Dismiss callback for Web and app setting details view.
@property(nonatomic, copy) ios::DismissASMViewControllerBlock
dismissWebAndAppSettingDetailsControllerBlock;
// Manages the authentication flow for a given identity.
@property(nonatomic, strong) AuthenticationFlow* authenticationFlow;
@end
......@@ -81,7 +92,9 @@
userPrefService:self.browser->GetBrowserState()->GetPrefs()];
self.mediator.syncSetupService = SyncSetupServiceFactory::GetForBrowserState(
self.browser->GetBrowserState());
self.mediator.authService = self.authService;
self.mediator.commandHandler = self;
self.mediator.syncErrorHandler = self;
self.viewController = [[ManageSyncSettingsTableViewController alloc]
initWithStyle:UITableViewStyleGrouped];
self.viewController.serviceDelegate = self.mediator;
......@@ -100,6 +113,11 @@
self.browser->GetBrowserState());
}
- (AuthenticationService*)authService {
return AuthenticationServiceFactory::GetForBrowserState(
self.browser->GetBrowserState());
}
#pragma mark - Private
// Closes the Manage sync settings view controller.
......@@ -137,6 +155,32 @@
#pragma mark - ManageSyncSettingsCommandHandler
- (void)openWebAppActivityDialog {
AuthenticationService* authService =
AuthenticationServiceFactory::GetForBrowserState(
self.browser->GetBrowserState());
base::RecordAction(base::UserMetricsAction(
"Signin_AccountSettings_GoogleActivityControlsClicked"));
self.dismissWebAndAppSettingDetailsControllerBlock =
ios::GetChromeBrowserProvider()
->GetChromeIdentityService()
->PresentWebAndAppSettingDetailsController(
authService->GetAuthenticatedIdentity(), self.viewController,
YES);
}
- (void)openDataFromChromeSyncWebPage {
GURL url = google_util::AppendGoogleLocaleParam(
GURL(kSyncGoogleDashboardURL),
GetApplicationContext()->GetApplicationLocale());
OpenNewTabCommand* command = [OpenNewTabCommand commandWithURLFromChrome:url];
id<ApplicationCommands> handler = HandlerForProtocol(
self.browser->GetCommandDispatcher(), ApplicationCommands);
[handler closeSettingsUIAndOpenURL:command];
}
#pragma mark - SyncErrorSettingsCommandHandler
- (void)openPassphraseDialog {
DCHECK(self.mediator.shouldEncryptionItemBeEnabled);
UIViewController<SettingsRootViewControlling>* controllerToPush;
......@@ -169,28 +213,44 @@
kSettings];
}
- (void)openWebAppActivityDialog {
AuthenticationService* authService =
- (void)restartAuthenticationFlow {
ChromeIdentity* authenticatedIdentity =
AuthenticationServiceFactory::GetForBrowserState(
self.browser->GetBrowserState());
base::RecordAction(base::UserMetricsAction(
"Signin_AccountSettings_GoogleActivityControlsClicked"));
self.dismissWebAndAppSettingDetailsControllerBlock =
ios::GetChromeBrowserProvider()
->GetChromeIdentityService()
->PresentWebAndAppSettingDetailsController(
authService->GetAuthenticatedIdentity(), self.viewController,
YES);
self.browser->GetBrowserState())
->GetAuthenticatedIdentity();
[self.viewController preventUserInteraction];
DCHECK(!self.authenticationFlow);
self.authenticationFlow =
[[AuthenticationFlow alloc] initWithBrowser:self.browser
identity:authenticatedIdentity
shouldClearData:SHOULD_CLEAR_DATA_USER_CHOICE
postSignInAction:POST_SIGNIN_ACTION_START_SYNC
presentingViewController:self.viewController];
self.authenticationFlow.dispatcher = HandlerForProtocol(
self.browser->GetCommandDispatcher(), BrowsingDataCommands);
__weak ManageSyncSettingsCoordinator* weakSelf = self;
[self.authenticationFlow startSignInWithCompletion:^(BOOL success) {
// TODO(crbug.com/889919): Needs to add histogram for |success|.
DCHECK(weakSelf.authenticationFlow);
weakSelf.authenticationFlow = nil;
[weakSelf.viewController allowUserInteraction];
}];
}
- (void)openDataFromChromeSyncWebPage {
GURL url = google_util::AppendGoogleLocaleParam(
GURL(kSyncGoogleDashboardURL),
GetApplicationContext()->GetApplicationLocale());
OpenNewTabCommand* command = [OpenNewTabCommand commandWithURLFromChrome:url];
id<ApplicationCommands> handler = HandlerForProtocol(
self.browser->GetCommandDispatcher(), ApplicationCommands);
[handler closeSettingsUIAndOpenURL:command];
- (void)openReauthDialogAsSyncIsInAuthError {
ChromeIdentity* identity = self.authService->GetAuthenticatedIdentity();
if (self.authService->HasCachedMDMErrorForIdentity(identity)) {
self.authService->ShowMDMErrorDialogForIdentity(identity);
return;
}
// Sync enters in a permanent auth error state when fetching an access token
// fails with invalid credentials. This corresponds to Gaia responding with an
// "invalid grant" error. The current implementation of the iOS SSOAuth
// library user by Chrome removes the identity from the device when receiving
// an "invalid grant" response, which leads to the account being also signed
// out of Chrome. So the sync permanent auth error is a transient state on
// iOS. The decision was to avoid handling this error in the UI, which means
// that the reauth dialog is not actually presented on iOS.
}
#pragma mark - SyncObserverModelBridge
......
......@@ -10,8 +10,10 @@
#import "ios/chrome/browser/ui/settings/google_services/manage_sync_settings_service_delegate.h"
#import "ios/chrome/browser/ui/settings/google_services/manage_sync_settings_view_controller_model_delegate.h"
@protocol SyncErrorSettingsCommandHandler;
@protocol ManageSyncSettingsCommandHandler;
@protocol ManageSyncSettingsConsumer;
class AuthenticationService;
class PrefService;
class SyncSetupService;
namespace syncer {
......@@ -27,8 +29,12 @@ class SyncService;
@property(nonatomic, weak) id<ManageSyncSettingsConsumer> consumer;
// Sync setup service.
@property(nonatomic, assign) SyncSetupService* syncSetupService;
// Authentication service.
@property(nonatomic, assign) AuthenticationService* authService;
// Command handler.
@property(nonatomic, weak) id<ManageSyncSettingsCommandHandler> commandHandler;
// Error command handler.
@property(nonatomic, weak) id<SyncErrorSettingsCommandHandler> syncErrorHandler;
// Returns YES if the encryption item should be enabled.
@property(nonatomic, assign, readonly) BOOL shouldEncryptionItemBeEnabled;
......
......@@ -90,6 +90,15 @@
withRowAnimation:UITableViewRowAnimationNone];
}
- (void)reloadSections:(NSIndexSet*)sections {
if (!self.tableViewModel) {
// No need to reload since the model has not been loaded yet.
return;
}
[self.tableView reloadSections:sections
withRowAnimation:UITableViewRowAnimationNone];
}
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView*)tableView
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_GOOGLE_SERVICES_SYNC_ERROR_SETTINGS_COMMAND_HANDLER_H_
#define IOS_CHROME_BROWSER_UI_SETTINGS_GOOGLE_SERVICES_SYNC_ERROR_SETTINGS_COMMAND_HANDLER_H_
// Protocol to communicate actions following Sync errors from the mediator to
// its coordinator.
@protocol SyncErrorSettingsCommandHandler <NSObject>
// Restarts the authentication flow.
- (void)restartAuthenticationFlow;
// Opens the reauth sync dialog.
- (void)openReauthDialogAsSyncIsInAuthError;
// Opens the passphrase dialog.
- (void)openPassphraseDialog;
// Opens the trusted vault reauthentication dialog.
- (void)openTrustedVaultReauth;
@end
#endif // IOS_CHROME_BROWSER_UI_SETTINGS_GOOGLE_SERVICES_SYNC_ERROR_SETTINGS_COMMAND_HANDLER_H_
......@@ -1482,6 +1482,9 @@ NSString* kDevViewSourceKey = @"DevViewSource";
[_privacyCoordinator stop];
_privacyCoordinator = nil;
[_manageSyncSettingsCoordinator stop];
_manageSyncSettingsCoordinator = nil;
_settingsHasBeenDismissed = YES;
DCHECK(!self.isSigninInProgress);
[_signinPromoViewMediator signinPromoViewIsRemoved];
......
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