Commit 3084c793 authored by John Z Wu's avatar John Z Wu Committed by Commit Bot

Change CWVSyncController to support regular sync instead of butter

- Remove flag for account wallet.
- Add API for users to give consent.
- Change CWVSyncControllerDataSource to be class property so that
  the sync/auth stack will be able to ask for tokens during setup.
- Add method to CWVSyncControllerDataSource to return all accounts.
  This is required by chromium to maintain the freshness of tokens.
- Clear all local data when sync stops until we can handle data
  migration situations.
- Simplify CWVSyncControllerDelegate's did stop sync method.

Change-Id: I1773c270958ecffa21aa5196c94c1510bc7084a0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1816641
Commit-Queue: John Wu <jzw@chromium.org>
Reviewed-by: default avatarHiroshi Ichikawa <ichikawa@chromium.org>
Cr-Commit-Position: refs/heads/master@{#699944}
parent 80e4879a
......@@ -19,9 +19,7 @@
#import "ios/web_view/internal/cwv_user_content_controller_internal.h"
#import "ios/web_view/internal/cwv_web_view_internal.h"
#include "ios/web_view/internal/passwords/web_view_password_store_factory.h"
#include "ios/web_view/internal/signin/ios_web_view_signin_client.h"
#include "ios/web_view/internal/signin/web_view_identity_manager_factory.h"
#include "ios/web_view/internal/signin/web_view_signin_client_factory.h"
#include "ios/web_view/internal/signin/web_view_signin_error_controller_factory.h"
#import "ios/web_view/internal/sync/cwv_sync_controller_internal.h"
#import "ios/web_view/internal/sync/web_view_profile_sync_service_factory.h"
......@@ -162,18 +160,15 @@ CWVWebViewConfiguration* gIncognitoConfiguration = nil;
SigninErrorController* signinErrorController =
ios_web_view::WebViewSigninErrorControllerFactory::GetForBrowserState(
self.browserState);
autofill::PersonalDataManager* personalDataManager =
ios_web_view::WebViewPersonalDataManagerFactory::GetForBrowserState(
self.browserState);
_syncController =
[[CWVSyncController alloc] initWithSyncService:syncService
identityManager:identityManager
signinErrorController:signinErrorController];
// Set the newly created CWVSyncController on IOSWebViewSigninClient to
// so access tokens can be fetched.
IOSWebViewSigninClient* signinClient =
ios_web_view::WebViewSigninClientFactory::GetForBrowserState(
self.browserState);
signinClient->SetSyncController(_syncController);
signinErrorController:signinErrorController
personalDataManager:personalDataManager];
}
return _syncController;
}
......
......@@ -15,8 +15,6 @@
#include "net/cookies/cookie_change_dispatcher.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
@class CWVSyncController;
namespace ios_web_view {
class WebViewBrowserState;
}
......@@ -54,10 +52,6 @@ class IOSWebViewSigninClient : public SigninClient {
GaiaAuthConsumer* consumer,
gaia::GaiaSource source) override;
// CWVSyncController setter/getter.
void SetSyncController(CWVSyncController* sync_controller);
CWVSyncController* GetSyncController() const;
private:
// Helper to delay callbacks until connection becomes online again.
std::unique_ptr<WaitForNetworkCallbackHelper> network_callback_helper_;
......@@ -68,10 +62,6 @@ class IOSWebViewSigninClient : public SigninClient {
scoped_refptr<content_settings::CookieSettings> cookie_settings_;
// Used to add and remove content settings observers.
scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
// Used by WebViewDeviceAccountsProviderImpl to fetch access
// tokens. Also used to notify of signout events. Held weak so this class
// does not determine |sync_controller_|'s lifetime.
__weak CWVSyncController* sync_controller_ = nil;
DISALLOW_COPY_AND_ASSIGN(IOSWebViewSigninClient);
};
......
......@@ -6,7 +6,6 @@
#include "components/signin/core/browser/cookie_settings_util.h"
#include "google_apis/gaia/gaia_auth_fetcher.h"
#import "ios/web_view/internal/sync/cwv_sync_controller_internal.h"
#include "ios/web_view/internal/web_view_browser_state.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
......@@ -70,7 +69,6 @@ void IOSWebViewSigninClient::PreSignOut(
base::OnceCallback<void(SignoutDecision)> on_signout_decision_reached,
signin_metrics::ProfileSignout signout_source_metric) {
std::move(on_signout_decision_reached).Run(SignoutDecision::ALLOW_SIGNOUT);
[sync_controller_ didSignoutWithSourceMetric:signout_source_metric];
}
void IOSWebViewSigninClient::DelayNetworkCall(base::OnceClosure callback) {
......@@ -84,11 +82,3 @@ std::unique_ptr<GaiaAuthFetcher> IOSWebViewSigninClient::CreateGaiaAuthFetcher(
GetURLLoaderFactory());
}
void IOSWebViewSigninClient::SetSyncController(
CWVSyncController* sync_controller) {
sync_controller_ = sync_controller;
}
CWVSyncController* IOSWebViewSigninClient::GetSyncController() const {
return sync_controller_;
}
......@@ -12,14 +12,10 @@
#include "base/macros.h"
#include "components/signin/public/identity_manager/ios/device_accounts_provider.h"
class IOSWebViewSigninClient;
// Implementation of DeviceAccountsProvider.
class WebViewDeviceAccountsProviderImpl : public DeviceAccountsProvider {
public:
// |signin_client| used to fetch access tokens.
explicit WebViewDeviceAccountsProviderImpl(
IOSWebViewSigninClient* signin_client);
WebViewDeviceAccountsProviderImpl();
~WebViewDeviceAccountsProviderImpl() override;
// ios::DeviceAccountsProvider
......@@ -33,9 +29,6 @@ class WebViewDeviceAccountsProviderImpl : public DeviceAccountsProvider {
NSError* error) const override;
private:
// Used to obtain access tokens in |GetAccessToken|.
IOSWebViewSigninClient* const signin_client_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(WebViewDeviceAccountsProviderImpl);
};
......
......@@ -6,17 +6,16 @@
#include "base/logging.h"
#include "base/strings/sys_string_conversions.h"
#include "ios/web_view/internal/signin/ios_web_view_signin_client.h"
#import "ios/web_view/internal/sync/cwv_sync_controller_internal.h"
#import "ios/web_view/public/cwv_identity.h"
#import "ios/web_view/public/cwv_sync_controller_data_source.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
WebViewDeviceAccountsProviderImpl::WebViewDeviceAccountsProviderImpl(
IOSWebViewSigninClient* signin_client)
: signin_client_(signin_client) {}
WebViewDeviceAccountsProviderImpl::WebViewDeviceAccountsProviderImpl() =
default;
WebViewDeviceAccountsProviderImpl::~WebViewDeviceAccountsProviderImpl() =
default;
......@@ -26,27 +25,42 @@ void WebViewDeviceAccountsProviderImpl::GetAccessToken(
const std::string& client_id,
const std::set<std::string>& scopes,
AccessTokenCallback callback) {
// |sync_controller| may still be nil if this is called too early so
// |callback| will not be invoked. That's OK because this will be called again
// after |sync_controller| has been set.
CWVSyncController* sync_controller = signin_client_->GetSyncController();
[sync_controller fetchAccessTokenForScopes:scopes
callback:std::move(callback)];
NSMutableArray<NSString*>* scopes_array = [NSMutableArray array];
for (const auto& scope : scopes) {
[scopes_array addObject:base::SysUTF8ToNSString(scope)];
}
// AccessTokenCallback is non-copyable. Using __block allocates the memory
// directly in the block object at compilation time (instead of doing a
// copy). This is required to have correct interaction between move-only
// types and Objective-C blocks.
__block AccessTokenCallback scoped_callback = std::move(callback);
CWVIdentity* identity =
[[CWVIdentity alloc] initWithEmail:nil
fullName:nil
gaiaID:base::SysUTF8ToNSString(gaia_id)];
[CWVSyncController.dataSource
fetchAccessTokenForIdentity:identity
scopes:scopes_array
completionHandler:^(NSString* access_token,
NSDate* expiration_date, NSError* error) {
std::move(scoped_callback)
.Run(access_token, expiration_date, error);
}];
}
std::vector<DeviceAccountsProvider::AccountInfo>
WebViewDeviceAccountsProviderImpl::GetAllAccounts() const {
// |sync_controller| may still be nil if this is called too early. That's OK
// because this will be called again after it has been set.
CWVSyncController* sync_controller = signin_client_->GetSyncController();
CWVIdentity* current_identity = sync_controller.currentIdentity;
if (current_identity) {
NSArray<CWVIdentity*>* identities =
[CWVSyncController.dataSource allKnownIdentities];
std::vector<AccountInfo> account_infos;
for (CWVIdentity* identity in identities) {
AccountInfo account_info;
account_info.email = base::SysNSStringToUTF8(current_identity.email);
account_info.gaia = base::SysNSStringToUTF8(current_identity.gaiaID);
return {account_info};
account_info.email = base::SysNSStringToUTF8(identity.email);
account_info.gaia = base::SysNSStringToUTF8(identity.gaiaID);
account_infos.push_back(account_info);
}
return {};
return account_infos;
}
AuthenticationErrorCategory
......
......@@ -61,22 +61,16 @@ WebViewIdentityManagerFactory::BuildServiceInstanceFor(
WebViewBrowserState* browser_state =
WebViewBrowserState::FromBrowserState(context);
// Clearing the sign in state on start up greatly simplifies the management of
// ChromeWebView's signin state.
PrefService* pref_service = browser_state->GetPrefs();
pref_service->ClearPref(prefs::kGoogleServicesAccountId);
pref_service->ClearPref(prefs::kGoogleServicesConsentedToSync);
IOSWebViewSigninClient* client =
WebViewSigninClientFactory::GetForBrowserState(browser_state);
signin::IdentityManagerBuildParams params;
params.account_consistency = signin::AccountConsistencyMethod::kDisabled;
params.device_accounts_provider =
std::make_unique<WebViewDeviceAccountsProviderImpl>(client);
std::make_unique<WebViewDeviceAccountsProviderImpl>();
params.image_decoder = image_fetcher::CreateIOSImageDecoder();
params.local_state = ApplicationContext::GetInstance()->GetLocalState();
params.pref_service = pref_service;
params.pref_service = browser_state->GetPrefs();
params.profile_path = base::FilePath();
params.signin_client = client;
......
......@@ -8,6 +8,7 @@
#include <memory>
#include "base/strings/sys_string_conversions.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/signin/core/browser/signin_error_controller.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/signin/public/identity_manager/device_accounts_synchronizer.h"
......@@ -24,8 +25,6 @@
#error "This file requires ARC support."
#endif
using AccessTokenCallback = DeviceAccountsProvider::AccessTokenCallback;
NSErrorDomain const CWVSyncErrorDomain =
@"org.chromium.chromewebview.SyncErrorDomain";
......@@ -65,6 +64,8 @@ CWVSyncError CWVConvertGoogleServiceAuthErrorStateToCWVSyncError(
- (void)didShutdownSync;
// Called by WebViewSyncControllerObserverBridge's |OnErrorChanged|.
- (void)didUpdateAuthError;
// Called by WebViewSyncControllerObserverBridge's |OnPrimaryAccountCleared|.
- (void)didClearPrimaryAccount;
// Call to refresh access tokens for |currentIdentity|.
- (void)reloadCredentials;
......@@ -77,6 +78,7 @@ namespace ios_web_view {
// methods on CWVSyncController.
class WebViewSyncControllerObserverBridge
: public syncer::SyncServiceObserver,
public signin::IdentityManager::Observer,
public SigninErrorController::Observer {
public:
explicit WebViewSyncControllerObserverBridge(
......@@ -92,6 +94,12 @@ class WebViewSyncControllerObserverBridge
[sync_controller_ didShutdownSync];
}
// signin::IdentityManager::Observer
void OnPrimaryAccountCleared(
const CoreAccountInfo& previous_primary_account_info) override {
[sync_controller_ didClearPrimaryAccount];
}
// SigninErrorController::Observer:
void OnErrorChanged() override { [sync_controller_ didUpdateAuthError]; }
......@@ -106,29 +114,51 @@ class WebViewSyncControllerObserverBridge
signin::IdentityManager* _identityManager;
SigninErrorController* _signinErrorController;
std::unique_ptr<ios_web_view::WebViewSyncControllerObserverBridge> _observer;
// Data source that can provide access tokens.
__weak id<CWVSyncControllerDataSource> _dataSource;
autofill::PersonalDataManager* _personalDataManager;
}
@synthesize delegate = _delegate;
@synthesize currentIdentity = _currentIdentity;
@synthesize delegate = _delegate;
namespace {
// Data source that can provide access tokens.
__weak id<CWVSyncControllerDataSource> gSyncDataSource;
}
- (instancetype)initWithSyncService:(syncer::SyncService*)syncService
identityManager:(signin::IdentityManager*)identityManager
signinErrorController:
(SigninErrorController*)signinErrorController {
+ (void)setDataSource:(id<CWVSyncControllerDataSource>)dataSource {
gSyncDataSource = dataSource;
}
+ (id<CWVSyncControllerDataSource>)dataSource {
return gSyncDataSource;
}
- (instancetype)
initWithSyncService:(syncer::SyncService*)syncService
identityManager:(signin::IdentityManager*)identityManager
signinErrorController:(SigninErrorController*)signinErrorController
personalDataManager:(autofill::PersonalDataManager*)personalDataManager {
self = [super init];
if (self) {
_syncService = syncService;
_identityManager = identityManager;
_signinErrorController = signinErrorController;
_personalDataManager = personalDataManager;
_observer =
std::make_unique<ios_web_view::WebViewSyncControllerObserverBridge>(
self);
_syncService->AddObserver(_observer.get());
_identityManager->AddObserver(_observer.get());
_signinErrorController->AddObserver(_observer.get());
if (_identityManager->HasPrimaryAccount()) {
CoreAccountInfo accountInfo = _identityManager->GetPrimaryAccountInfo();
_currentIdentity = [[CWVIdentity alloc]
initWithEmail:base::SysUTF8ToNSString(accountInfo.email)
fullName:nil
gaiaID:base::SysUTF8ToNSString(accountInfo.gaia)];
}
// Refresh access tokens on foreground to extend expiration dates.
[[NSNotificationCenter defaultCenter]
addObserver:self
......@@ -141,6 +171,7 @@ class WebViewSyncControllerObserverBridge
- (void)dealloc {
_syncService->RemoveObserver(_observer.get());
_identityManager->RemoveObserver(_observer.get());
_signinErrorController->RemoveObserver(_observer.get());
}
......@@ -150,17 +181,15 @@ class WebViewSyncControllerObserverBridge
return _syncService->GetUserSettings()->IsPassphraseRequiredForDecryption();
}
- (void)startSyncWithIdentity:(CWVIdentity*)identity
dataSource:
(__weak id<CWVSyncControllerDataSource>)dataSource {
DCHECK(!_dataSource);
DCHECK(!_currentIdentity);
- (BOOL)isConsentNeeded {
return !_syncService->GetUserSettings()->IsFirstSetupComplete();
}
_dataSource = dataSource;
_currentIdentity = identity;
- (void)startSyncWithIdentity:(CWVIdentity*)identity {
DCHECK(!_currentIdentity)
<< "Already syncing! Call -stopSyncAndClearIdentity first.";
DCHECK(_dataSource);
DCHECK(_currentIdentity);
_currentIdentity = identity;
const CoreAccountId accountId = _identityManager->PickAccountIdForAccount(
base::SysNSStringToUTF8(identity.gaiaID),
......@@ -172,16 +201,23 @@ class WebViewSyncControllerObserverBridge
_identityManager->GetPrimaryAccountMutator()->SetPrimaryAccount(accountId);
CHECK_EQ(_identityManager->GetPrimaryAccountId(), accountId);
_syncService->GetUserSettings()->SetSyncRequested(true);
}
- (void)stopSyncAndClearIdentity {
_syncService->StopAndClear();
auto* primaryAccountMutator = _identityManager->GetPrimaryAccountMutator();
primaryAccountMutator->ClearPrimaryAccount(
signin::PrimaryAccountMutator::ClearAccountsAction::kDefault,
signin_metrics::ProfileSignout::USER_CLICKED_SIGNOUT_SETTINGS,
signin_metrics::SignoutDelete::IGNORE_METRIC);
// Clear all local data because we do not support data migration.
_personalDataManager->ClearAllLocalData();
_currentIdentity = nil;
_dataSource = nil;
}
- (BOOL)unlockWithPassphrase:(NSString*)passphrase {
......@@ -189,6 +225,11 @@ class WebViewSyncControllerObserverBridge
base::SysNSStringToUTF8(passphrase));
}
- (void)consent {
_syncService->GetUserSettings()->SetFirstSetupComplete(
syncer::SyncFirstSetupCompleteSource::BASIC_FLOW);
}
#pragma mark - Private Methods
- (void)didCompleteSyncConfiguration {
......@@ -203,50 +244,17 @@ class WebViewSyncControllerObserverBridge
}
- (void)reloadCredentials {
if (_currentIdentity != nil) {
_identityManager->GetDeviceAccountsSynchronizer()
->ReloadAllAccountsFromSystem();
}
_identityManager->GetDeviceAccountsSynchronizer()
->ReloadAllAccountsFromSystem();
}
#pragma mark - Internal Methods
- (void)fetchAccessTokenForScopes:(const std::set<std::string>&)scopes
callback:(AccessTokenCallback)callback {
DCHECK(!callback.is_null());
NSMutableArray<NSString*>* scopesArray = [NSMutableArray array];
for (const auto& scope : scopes) {
[scopesArray addObject:base::SysUTF8ToNSString(scope)];
}
// AccessTokenCallback is non-copyable. Using __block allocates the memory
// directly in the block object at compilation time (instead of doing a
// copy). This is required to have correct interaction between move-only
// types and Objective-C blocks.
__block AccessTokenCallback scopedCallback = std::move(callback);
[_dataSource syncController:self
getAccessTokenForScopes:[scopesArray copy]
completionHandler:^(NSString* accessToken, NSDate* expirationDate,
NSError* error) {
std::move(scopedCallback).Run(accessToken, expirationDate, error);
}];
}
- (void)didSignoutWithSourceMetric:(signin_metrics::ProfileSignout)metric {
if (![_delegate respondsToSelector:@selector
(syncController:didStopSyncWithReason:)]) {
return;
}
CWVStopSyncReason reason;
if (metric == signin_metrics::ProfileSignout::USER_CLICKED_SIGNOUT_SETTINGS) {
reason = CWVStopSyncReasonClient;
} else if (metric == signin_metrics::ProfileSignout::SERVER_FORCED_DISABLE) {
reason = CWVStopSyncReasonServer;
} else {
NOTREACHED();
- (void)didClearPrimaryAccount {
if (![_delegate respondsToSelector:@selector(syncControllerDidStopSync:)]) {
return;
}
[_delegate syncController:self didStopSyncWithReason:reason];
[_delegate syncControllerDidStopSync:self];
}
- (void)didUpdateAuthError {
......
......@@ -5,15 +5,14 @@
#ifndef IOS_WEB_VIEW_INTERNAL_SYNC_CWV_SYNC_CONTROLLER_INTERNAL_H_
#define IOS_WEB_VIEW_INTERNAL_SYNC_CWV_SYNC_CONTROLLER_INTERNAL_H_
#include <set>
#include "components/signin/public/base/signin_metrics.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "ios/web_view/internal/signin/web_view_device_accounts_provider_impl.h"
#import "ios/web_view/public/cwv_sync_controller.h"
NS_ASSUME_NONNULL_BEGIN
namespace autofill {
class PersonalDataManager;
} // autofill
namespace syncer {
class SyncService;
} // namespace syncer
......@@ -27,21 +26,13 @@ class SigninErrorController;
@interface CWVSyncController ()
// All dependencies must out live this class.
- (instancetype)initWithSyncService:(syncer::SyncService*)syncService
identityManager:(signin::IdentityManager*)identityManager
signinErrorController:
(SigninErrorController*)SigninErrorController
- (instancetype)
initWithSyncService:(syncer::SyncService*)syncService
identityManager:(signin::IdentityManager*)identityManager
signinErrorController:(SigninErrorController*)signinErrorController
personalDataManager:(autofill::PersonalDataManager*)personalDataManager
NS_DESIGNATED_INITIALIZER;
// Called by WebViewDeviceAccountsProviderImpl to obtain
// access tokens for |scopes| to be passed back in |callback|.
- (void)fetchAccessTokenForScopes:(const std::set<std::string>&)scopes
callback:(DeviceAccountsProvider::AccessTokenCallback)
callback;
// Called by IOSWebViewSigninClient when signing out.
- (void)didSignoutWithSourceMetric:(signin_metrics::ProfileSignout)metric;
@end
NS_ASSUME_NONNULL_END
......
......@@ -11,9 +11,12 @@
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/test/bind_test_util.h"
#include "components/autofill/core/browser/test_personal_data_manager.h"
#include "components/signin/core/browser/signin_error_controller.h"
#include "components/signin/public/base/account_consistency_method.h"
#include "components/signin/public/base/signin_pref_names.h"
#include "components/signin/public/identity_manager/identity_test_utils.h"
#include "components/signin/public/identity_manager/primary_account_mutator.h"
#include "components/sync/driver/mock_sync_service.h"
#include "components/sync/driver/sync_service_observer.h"
#include "google_apis/gaia/google_service_auth_error.h"
......@@ -21,6 +24,7 @@
#include "ios/web/public/test/web_task_environment.h"
#include "ios/web_view/internal/app/application_context.h"
#include "ios/web_view/internal/signin/ios_web_view_signin_client.h"
#include "ios/web_view/internal/signin/web_view_device_accounts_provider_impl.h"
#include "ios/web_view/internal/signin/web_view_identity_manager_factory.h"
#include "ios/web_view/internal/signin/web_view_signin_client_factory.h"
#include "ios/web_view/internal/signin/web_view_signin_error_controller_factory.h"
......@@ -64,23 +68,31 @@ std::unique_ptr<KeyedService> BuildMockSyncService(web::BrowserState* context) {
class CWVSyncControllerTest : public TestWithLocaleAndResources {
protected:
CWVSyncControllerTest() : browser_state_(/*off_the_record=*/false) {
// Clear account info before each test.
PrefService* pref_service = browser_state_.GetPrefs();
pref_service->ClearPref(prefs::kGoogleServicesAccountId);
pref_service->ClearPref(prefs::kGoogleServicesConsentedToSync);
pref_service->ClearPref(prefs::kAccountInfo);
WebViewProfileSyncServiceFactory::GetInstance()->SetTestingFactory(
&browser_state_, base::BindRepeating(&BuildMockSyncService));
EXPECT_CALL(*mock_sync_service(), AddObserver(_))
.WillOnce(Invoke(this, &CWVSyncControllerTest::AddObserver));
personal_data_manager_ =
std::make_unique<autofill::TestPersonalDataManager>();
sync_controller_ = [[CWVSyncController alloc]
initWithSyncService:mock_sync_service()
identityManager:identity_manager()
signinErrorController:signin_error_controller()];
WebViewSigninClientFactory::GetForBrowserState(&browser_state_)
->SetSyncController(sync_controller_);
signinErrorController:signin_error_controller()
personalDataManager:personal_data_manager_.get()];
}
~CWVSyncControllerTest() override {
EXPECT_CALL(*mock_sync_service(), RemoveObserver(_));
EXPECT_CALL(*mock_sync_service(), Shutdown());
}
void AddObserver(syncer::SyncServiceObserver* observer) {
......@@ -103,6 +115,7 @@ class CWVSyncControllerTest : public TestWithLocaleAndResources {
web::WebTaskEnvironment task_environment_;
ios_web_view::WebViewBrowserState browser_state_;
std::unique_ptr<autofill::TestPersonalDataManager> personal_data_manager_;
CWVSyncController* sync_controller_ = nil;
syncer::SyncServiceObserver* sync_service_observer_ = nullptr;
};
......@@ -114,23 +127,23 @@ TEST_F(CWVSyncControllerTest, DataSourceCallbacks) {
// destroyed before this test exits to avoid holding on to |sync_controller_|.
@autoreleasepool {
id data_source = OCMProtocolMock(@protocol(CWVSyncControllerDataSource));
CWVSyncController.dataSource = data_source;
[[data_source expect]
syncController:sync_controller_
getAccessTokenForScopes:[OCMArg checkWithBlock:^BOOL(NSArray* scopes) {
return [scopes containsObject:@(kTestScope1)] &&
[scopes containsObject:@(kTestScope2)];
fetchAccessTokenForIdentity:[OCMArg checkWithBlock:^BOOL(
CWVIdentity* identity) {
return [identity.gaiaID isEqualToString:@(kTestGaiaId)];
}]
completionHandler:[OCMArg any]];
CWVIdentity* identity = [[CWVIdentity alloc] initWithEmail:@(kTestEmail)
fullName:@(kTestFullName)
gaiaID:@(kTestGaiaId)];
[sync_controller_ startSyncWithIdentity:identity dataSource:data_source];
scopes:[OCMArg checkWithBlock:^BOOL(
NSArray* scopes) {
return [scopes containsObject:@(kTestScope1)] &&
[scopes containsObject:@(kTestScope2)];
}]
completionHandler:[OCMArg any]];
WebViewDeviceAccountsProviderImpl accounts_provider;
std::set<std::string> scopes = {kTestScope1, kTestScope2};
[sync_controller_ fetchAccessTokenForScopes:scopes
callback:base::DoNothing()];
accounts_provider.GetAccessToken(kTestGaiaId, "dummy-client-id", scopes,
base::DoNothing());
[data_source verify];
}
......@@ -142,8 +155,15 @@ TEST_F(CWVSyncControllerTest, DelegateCallbacks) {
// [delegate expect] returns an autoreleased object, but it must be destroyed
// before this test exits to avoid holding on to |sync_controller_|.
@autoreleasepool {
CWVIdentity* identity = [[CWVIdentity alloc] initWithEmail:@(kTestEmail)
fullName:@(kTestFullName)
gaiaID:@(kTestGaiaId)];
id data_source = OCMProtocolMock(@protocol(CWVSyncControllerDataSource));
[[[data_source stub] andReturn:@[ identity ]] allKnownIdentities];
CWVSyncController.dataSource = data_source;
id delegate = OCMProtocolMock(@protocol(CWVSyncControllerDelegate));
sync_controller_.delegate = delegate;
[sync_controller_ startSyncWithIdentity:identity];
[[delegate expect] syncControllerDidStartSync:sync_controller_];
sync_service_observer_->OnSyncConfigurationCompleted(mock_sync_service());
......@@ -153,13 +173,6 @@ TEST_F(CWVSyncControllerTest, DelegateCallbacks) {
return error.code == CWVSyncErrorInvalidGAIACredentials;
}]];
id data_source = OCMProtocolMock(@protocol(CWVSyncControllerDataSource));
CWVIdentity* identity = [[CWVIdentity alloc] initWithEmail:@(kTestEmail)
fullName:@(kTestFullName)
gaiaID:@(kTestGaiaId)];
[sync_controller_ startSyncWithIdentity:identity dataSource:data_source];
// Create authentication error.
GoogleServiceAuthError auth_error(
GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
......@@ -167,11 +180,12 @@ TEST_F(CWVSyncControllerTest, DelegateCallbacks) {
identity_manager(), identity_manager()->GetPrimaryAccountId(),
auth_error);
[[delegate expect] syncController:sync_controller_
didStopSyncWithReason:CWVStopSyncReasonServer];
[sync_controller_
didSignoutWithSourceMetric:signin_metrics::ProfileSignout::
SERVER_FORCED_DISABLE];
[[delegate expect] syncControllerDidStopSync:sync_controller_];
identity_manager()->GetPrimaryAccountMutator()->ClearPrimaryAccount(
signin::PrimaryAccountMutator::ClearAccountsAction::kDefault,
signin_metrics::ProfileSignout::USER_CLICKED_SIGNOUT_SETTINGS,
signin_metrics::SignoutDelete::IGNORE_METRIC);
[delegate verify];
}
}
......@@ -181,18 +195,36 @@ TEST_F(CWVSyncControllerTest, CurrentIdentity) {
CWVIdentity* identity = [[CWVIdentity alloc] initWithEmail:@(kTestEmail)
fullName:@(kTestFullName)
gaiaID:@(kTestGaiaId)];
id unused_mock = OCMProtocolMock(@protocol(CWVSyncControllerDataSource));
[sync_controller_ startSyncWithIdentity:identity dataSource:unused_mock];
id data_source = OCMProtocolMock(@protocol(CWVSyncControllerDataSource));
[[[data_source stub] andReturn:@[ identity ]] allKnownIdentities];
CWVSyncController.dataSource = data_source;
[sync_controller_ startSyncWithIdentity:identity];
CWVIdentity* currentIdentity = sync_controller_.currentIdentity;
EXPECT_TRUE(currentIdentity);
EXPECT_NSEQ(identity.email, currentIdentity.email);
EXPECT_NSEQ(identity.fullName, currentIdentity.fullName);
EXPECT_NSEQ(identity.gaiaID, currentIdentity.gaiaID);
EXPECT_CALL(*mock_sync_service(), StopAndClear());
[sync_controller_ stopSyncAndClearIdentity];
EXPECT_FALSE(sync_controller_.currentIdentity);
}
// Verifies CWVSyncController's consent API.
TEST_F(CWVSyncControllerTest, Consent) {
EXPECT_CALL(*mock_sync_service()->GetMockUserSettings(),
IsFirstSetupComplete())
.WillOnce(Return(false));
EXPECT_TRUE(sync_controller_.consentNeeded);
EXPECT_CALL(*mock_sync_service()->GetMockUserSettings(),
SetFirstSetupComplete(_));
[sync_controller_ consent];
EXPECT_CALL(*mock_sync_service()->GetMockUserSettings(),
IsFirstSetupComplete())
.WillOnce(Return(true));
EXPECT_FALSE(sync_controller_.consentNeeded);
}
// Verifies CWVSyncController's passphrase API.
TEST_F(CWVSyncControllerTest, Passphrase) {
EXPECT_CALL(*mock_sync_service()->GetMockUserSettings(),
......
......@@ -46,12 +46,11 @@ namespace ios_web_view {
namespace {
syncer::ModelTypeSet GetDisabledTypes() {
// Only want credit card autofill for now.
// TODO(crbug.com/906910): Remove syncer::AUTOFILL_PROFILE and
// syncer::PASSWORDS as well once they are ready.
syncer::ModelTypeSet disabled_types = syncer::UserTypes();
disabled_types.Remove(syncer::AUTOFILL_WALLET_DATA);
disabled_types.Remove(syncer::AUTOFILL_WALLET_METADATA);
disabled_types.Remove(syncer::AUTOFILL_PROFILE);
disabled_types.Remove(syncer::PASSWORDS);
return disabled_types;
}
} // namespace
......
......@@ -26,6 +26,7 @@
#include "components/signin/ios/browser/active_state_manager.h"
#include "components/sync/base/pref_names.h"
#include "components/sync/base/sync_prefs.h"
#include "components/sync_device_info/device_info_prefs.h"
#include "components/sync_sessions/session_sync_prefs.h"
#include "components/translate/core/browser/translate_pref_names.h"
#include "components/translate/core/browser/translate_prefs.h"
......@@ -179,6 +180,7 @@ void WebViewBrowserState::RegisterPrefs(
gcm::GCMChannelStatusSyncer::RegisterProfilePrefs(pref_registry);
sync_sessions::SessionSyncPrefs::RegisterProfilePrefs(pref_registry);
syncer::SyncPrefs::RegisterProfilePrefs(pref_registry);
syncer::DeviceInfoPrefs::RegisterProfilePrefs(pref_registry);
#endif // BUILDFLAG(IOS_WEB_VIEW_ENABLE_SYNC)
// Instantiate all factories to setup dependency graph for pref registration.
......
......@@ -50,10 +50,8 @@ void WebViewWebMainParts::PreCreateThreads() {
#if BUILDFLAG(IOS_WEB_VIEW_ENABLE_SYNC)
std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
std::string enable_features = base::JoinString(
{autofill::features::kAutofillEnableAccountWalletStorage.name,
autofill::features::kAutofillUpstream.name},
",");
std::string enable_features =
base::JoinString({autofill::features::kAutofillUpstream.name}, ",");
std::string disabled_features = base::JoinString(
{// Allows form_structure.cc to run heuristics on single field forms.
// This is needed to find autofillable password forms with less than 3
......
......@@ -15,14 +15,14 @@ NS_ASSUME_NONNULL_BEGIN
CWV_EXPORT
@interface CWVIdentity : NSObject
- (instancetype)initWithEmail:(NSString*)email
- (instancetype)initWithEmail:(nullable NSString*)email
fullName:(nullable NSString*)fullName
gaiaID:(NSString*)gaiaID NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
// The user's email address. e.g. john.doe@chromium.org.
@property(nonatomic, copy, readonly) NSString* email;
@property(nonatomic, copy, readonly, nullable) NSString* email;
// The user's full name. e.g. John Doe.
@property(nonatomic, copy, readonly, nullable) NSString* fullName;
......
......@@ -42,14 +42,16 @@ typedef NS_ENUM(NSInteger, CWVSyncError) {
};
// Used to manage syncing for autofill and password data. Usage:
// 1. Call |startSyncWithIdentity:dataSource:| to start syncing with identity.
// 2. Call |stopSyncAndClearIdentity| to stop syncing.
// It is necessary to call |startSyncWithIdentity:dataSource:| once per cold app
// launch to keep |currentIdentity| syncing. Remember to set the |delegate| to
// listen to sync start and stop events.
// 1. Set the |dataSource| and |delegate|.
// 2. Call |startSyncWithIdentity:| to start syncing with identity.
// 3. Call |stopSyncAndClearIdentity| to stop syncing.
CWV_EXPORT
@interface CWVSyncController : NSObject
// The data source of CWVSyncController.
@property(class, nonatomic, weak, nullable) id<CWVSyncControllerDataSource>
dataSource;
// The delegate of CWVSyncController.
@property(nonatomic, weak, nullable) id<CWVSyncControllerDelegate> delegate;
......@@ -61,24 +63,36 @@ CWV_EXPORT
// is invoked in |delegate|.
@property(nonatomic, readonly, getter=isPassphraseNeeded) BOOL passphraseNeeded;
// Whether or not |currentIdentity| has opted into sync. Not meaningful
// until |currentIdentity| is set and |syncControllerDidStartSync:| callback in
// is invoked in |delegate|.
@property(nonatomic, readonly, getter=isConsentNeeded) BOOL consentNeeded;
- (instancetype)init NS_UNAVAILABLE;
// Start syncing with |identity|. |dataSource| is used to obtain access tokens.
// Start syncing with |identity|.
// |identity| will be persisted as |currentIdentity| and continue syncing until
// |stopSyncAndClearIdentity| is called or the app is restarted.
- (void)startSyncWithIdentity:(CWVIdentity*)identity
dataSource:
(__weak id<CWVSyncControllerDataSource>)dataSource;
// |stopSyncAndClearIdentity| is called.
// Make sure |dataSource| is set so access tokens can be fetched.
- (void)startSyncWithIdentity:(CWVIdentity*)identity;
// Stops syncs and nils out |currentIdentity|. This method is idempotent.
- (void)stopSyncAndClearIdentity;
// If |passphraseNeeded| is |YES|. Call this to unlock the sync data.
// Only call after calling |startSyncWithIdentity:dataSource:| and receiving
// Only call after calling |startSyncWithIdentity:| and receiving
// |syncControllerDidStartSync:| callback in |delegate|.
// No op if |passphraseNeeded| is |NO|. Returns |YES| if successful.
- (BOOL)unlockWithPassphrase:(NSString*)passphrase;
// If |consentNeeded| is |YES|, call this method to opt the |currentIdentity|
// into sync. Notes:
// - Only call after calling |startSyncWithIdentity:| and receiving
// |syncControllerDidStartSync:| callback in |delegate|.
// - Only call after receiving explicit consent from the user. For example,
// user accepts an opt-in UI prompt.
- (void)consent;
@end
NS_ASSUME_NONNULL_END
......
......@@ -9,22 +9,27 @@
NS_ASSUME_NONNULL_BEGIN
@class CWVSyncController;
@class CWVIdentity;
// Data source of CWVSyncController.
@protocol CWVSyncControllerDataSource<NSObject>
// Called when access tokens are requested.
// |identity| The user whose access tokens are requested.
// |scopes| OAuth scopes requested.
// |completionHandler| Use to pass back token information.
// If successful, only |accessToken| and |expirationDate| should be non-nil.
// If unsuccessful, only |error| should be non-nil.
- (void)syncController:(CWVSyncController*)syncController
getAccessTokenForScopes:(NSArray<NSString*>*)scopes
completionHandler:
(void (^)(NSString* _Nullable accessToken,
NSDate* _Nullable expirationDate,
NSError* _Nullable error))completionHandler;
// If successful, only |accessToken| and |expirationDate| will be non-nil.
// If unsuccessful, only |error| will be non-nil.
- (void)fetchAccessTokenForIdentity:(CWVIdentity*)identity
scopes:(NSArray<NSString*>*)scopes
completionHandler:
(void (^)(NSString* _Nullable accessToken,
NSDate* _Nullable expirationDate,
NSError* _Nullable error))completionHandler;
// Return all available identities. This is used internally to track if accounts
// become stale and need to be removed.
- (NSArray<CWVIdentity*>*)allKnownIdentities;
@end
......
......@@ -9,13 +9,6 @@
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger, CWVStopSyncReason) {
// When sync is stopped explicitly via |stopSyncAndClearIdentity|.
CWVStopSyncReasonClient = 0,
// When sync was reset from another device.
CWVStopSyncReasonServer = 1
};
@class CWVSyncController;
// Delegate of CWVSyncController.
......@@ -23,8 +16,9 @@ typedef NS_ENUM(NSInteger, CWVStopSyncReason) {
@optional
// Called when sync has been started. Check |syncController|'s |needsPassphrase|
// property to see if |unlockWithPassphrase:| is necessary.
// Called when sync has started. Check |syncController|'s |passphraseNeeded|
// property to see if |unlockWithPassphrase:| is necessary, and also check
// |consentNeeded| to see if |consent| is necessary.
- (void)syncControllerDidStartSync:(CWVSyncController*)syncController;
// Called when sync fails. |error|'s code is a CWVSyncError.
......@@ -32,9 +26,8 @@ typedef NS_ENUM(NSInteger, CWVStopSyncReason) {
- (void)syncController:(CWVSyncController*)syncController
didFailWithError:(NSError*)error;
// Called after sync was stopped. |reason| Indicates why sync was stopped.
- (void)syncController:(CWVSyncController*)syncController
didStopSyncWithReason:(CWVStopSyncReason)reason;
// Called after sync has stopped.
- (void)syncControllerDidStopSync:(CWVSyncController*)syncController;
@end
......
......@@ -17,11 +17,12 @@
#pragma mark CWVSyncControllerDataSource
- (void)syncController:(CWVSyncController*)syncController
getAccessTokenForScopes:(NSArray<NSString*>*)scopes
completionHandler:(void (^)(NSString* accessToken,
NSDate* expirationDate,
NSError* error))completionHandler {
- (void)fetchAccessTokenForIdentity:(CWVIdentity*)identity
scopes:(NSArray<NSString*>*)scopes
completionHandler:
(void (^)(NSString* _Nullable accessToken,
NSDate* _Nullable expirationDate,
NSError* _Nullable error))completionHandler {
// Always returns an error.
if (completionHandler) {
completionHandler(
......@@ -32,4 +33,8 @@
}
}
- (NSArray<CWVIdentity*>*)allKnownIdentities {
return [self identities];
}
@end
......@@ -350,9 +350,7 @@ NSString* const kWebViewShellJavaScriptDialogTextFieldAccessibiltyIdentifier =
CWVSyncController* syncController =
weakSelf.webView.configuration
.syncController;
[syncController
startSyncWithIdentity:identity
dataSource:_authService];
[syncController startSyncWithIdentity:identity];
}]];
}
......@@ -745,9 +743,8 @@ NSString* const kWebViewShellJavaScriptDialogTextFieldAccessibiltyIdentifier =
NSLog(@"%@:%@", NSStringFromSelector(_cmd), error);
}
- (void)syncController:(CWVSyncController*)syncController
didStopSyncWithReason:(CWVStopSyncReason)reason {
NSLog(@"%@:%ld", NSStringFromSelector(_cmd), (long)reason);
- (void)syncControllerDidStopSync:(CWVSyncController*)syncController {
NSLog(@"%@", NSStringFromSelector(_cmd));
}
@end
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