diff options
author | sdefresne <sdefresne@chromium.org> | 2015-05-20 08:26:52 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-05-20 15:27:00 +0000 |
commit | 5548199bedbf5452f0655aa236bebed3726ea1f2 (patch) | |
tree | ce383c529af1a67e37f3bcf21612e02a6b2a5bce /ios/chrome/browser/sync | |
parent | 2d90256078aca21c9ada9ec7699662596796d65c (diff) | |
download | chromium_src-5548199bedbf5452f0655aa236bebed3726ea1f2.zip chromium_src-5548199bedbf5452f0655aa236bebed3726ea1f2.tar.gz chromium_src-5548199bedbf5452f0655aa236bebed3726ea1f2.tar.bz2 |
[iOS] Upstream SyncSetupService (and mock)
SyncSetupService allows configuring sync. It handles enabling and disabling it,
as well as choosing datatypes. Most actions are delayed until a commit is done,
to allow the complex sync setup flow on iOS.
BUG=429756
Review URL: https://codereview.chromium.org/1148573002
Cr-Commit-Position: refs/heads/master@{#330736}
Diffstat (limited to 'ios/chrome/browser/sync')
-rw-r--r-- | ios/chrome/browser/sync/sync_setup_service.cc | 196 | ||||
-rw-r--r-- | ios/chrome/browser/sync/sync_setup_service.h | 111 | ||||
-rw-r--r-- | ios/chrome/browser/sync/sync_setup_service_mock.cc | 14 | ||||
-rw-r--r-- | ios/chrome/browser/sync/sync_setup_service_mock.h | 28 |
4 files changed, 349 insertions, 0 deletions
diff --git a/ios/chrome/browser/sync/sync_setup_service.cc b/ios/chrome/browser/sync/sync_setup_service.cc new file mode 100644 index 0000000..d617324 --- /dev/null +++ b/ios/chrome/browser/sync/sync_setup_service.cc @@ -0,0 +1,196 @@ +// Copyright 2012 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. + +#include "ios/chrome/browser/sync/sync_setup_service.h" + +#include <stdio.h> + +#include "base/prefs/pref_service.h" +#include "components/sync_driver/sync_prefs.h" +#include "components/sync_driver/sync_service.h" +#include "google_apis/gaia/google_service_auth_error.h" +#include "ios/chrome/browser/pref_names.h" +#include "ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h" +#include "net/base/network_change_notifier.h" +#include "sync/protocol/sync_protocol_error.h" + +namespace { +// The set of user-selectable datatypes. This must be in the same order as +// |SyncSetupService::SyncableDatatype|. +syncer::ModelType kDataTypes[] = { + syncer::BOOKMARKS, + syncer::TYPED_URLS, + syncer::PASSWORDS, + syncer::PROXY_TABS, + syncer::AUTOFILL, +}; +} // namespace + +SyncSetupService::SyncSetupService(sync_driver::SyncService* sync_service, + PrefService* prefs) + : sync_service_(sync_service), prefs_(prefs) { + DCHECK(sync_service_); + DCHECK(prefs_); + for (unsigned int i = 0; i < arraysize(kDataTypes); ++i) { + user_selectable_types_.Put(kDataTypes[i]); + } +} + +SyncSetupService::~SyncSetupService() { +} + +syncer::ModelType SyncSetupService::GetModelType(SyncableDatatype datatype) { + DCHECK(datatype < arraysize(kDataTypes)); + return kDataTypes[datatype]; +} + +syncer::ModelTypeSet SyncSetupService::GetDataTypes() const { + return sync_service_->GetPreferredDataTypes(); +} + +bool SyncSetupService::IsDataTypeEnabled(syncer::ModelType datatype) const { + return GetDataTypes().Has(datatype); +} + +void SyncSetupService::SetDataTypeEnabled(syncer::ModelType datatype, + bool enabled) { + sync_service_->SetSetupInProgress(true); + syncer::ModelTypeSet types = GetDataTypes(); + if (enabled) + types.Put(datatype); + else + types.Remove(datatype); + types.RetainAll(user_selectable_types_); + if (enabled && !IsSyncEnabled()) + SetSyncEnabledWithoutChangingDatatypes(true); + sync_service_->OnUserChoseDatatypes(IsSyncingAllDataTypes(), types); + if (GetDataTypes().Empty()) + SetSyncEnabled(false); +} + +bool SyncSetupService::UserActionIsRequiredToHaveSyncWork() { + if (!IsSyncEnabled() || !IsDataTypeEnabled(syncer::PROXY_TABS)) { + return true; + } + switch (this->GetSyncServiceState()) { + // No error. + case SyncSetupService::kNoSyncServiceError: + // These errors are transient and don't mean that sync is off. + case SyncSetupService::kSyncServiceCouldNotConnect: + case SyncSetupService::kSyncServiceServiceUnavailable: + return false; + // These errors effectively amount to disabled sync and require a signin. + case SyncSetupService::kSyncServiceSignInNeedsUpdate: + case SyncSetupService::kSyncServiceNeedsPassphrase: + case SyncSetupService::kSyncServiceUnrecoverableError: + return true; + default: + NOTREACHED() << "Unknown sync service state."; + return true; + } +} + +bool SyncSetupService::IsSyncingAllDataTypes() const { + sync_driver::SyncPrefs sync_prefs(prefs_); + return sync_prefs.HasKeepEverythingSynced(); +} + +void SyncSetupService::SetSyncingAllDataTypes(bool sync_all) { + sync_service_->SetSetupInProgress(true); + if (sync_all && !IsSyncEnabled()) + SetSyncEnabled(true); + sync_service_->OnUserChoseDatatypes(sync_all, GetDataTypes()); +} + +bool SyncSetupService::IsSyncEnabled() const { + return sync_service_->IsSyncEnabledAndLoggedIn(); +} + +void SyncSetupService::SetSyncEnabled(bool sync_enabled) { + SetSyncEnabledWithoutChangingDatatypes(sync_enabled); + if (sync_enabled && GetDataTypes().Empty()) + SetSyncingAllDataTypes(true); +} + +SyncSetupService::SyncServiceState SyncSetupService::GetSyncServiceState() { + switch (sync_service_->GetAuthError().state()) { + case GoogleServiceAuthError::REQUEST_CANCELED: + return kSyncServiceCouldNotConnect; + // Based on sync_ui_util::GetStatusLabelsForAuthError, SERVICE_UNAVAILABLE + // corresponds to sync having been disabled for the user's domain. + case GoogleServiceAuthError::SERVICE_UNAVAILABLE: + return kSyncServiceServiceUnavailable; + case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: + return kSyncServiceSignInNeedsUpdate; + // The following errors are not shown to the user. + case GoogleServiceAuthError::NONE: + // Connection failed is not shown to the user, as this will happen if the + // service retuned a 500 error. A more detail error can always be checked + // on about:sync. + case GoogleServiceAuthError::CONNECTION_FAILED: + case GoogleServiceAuthError::USER_NOT_SIGNED_UP: + case GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE: + break; + // The following errors are unexpected on iOS. + case GoogleServiceAuthError::CAPTCHA_REQUIRED: + case GoogleServiceAuthError::ACCOUNT_DELETED: + case GoogleServiceAuthError::ACCOUNT_DISABLED: + case GoogleServiceAuthError::TWO_FACTOR: + case GoogleServiceAuthError::HOSTED_NOT_ALLOWED: + case GoogleServiceAuthError::SERVICE_ERROR: + case GoogleServiceAuthError::WEB_LOGIN_REQUIRED: + // Conventional value for counting the states, never used. + case GoogleServiceAuthError::NUM_STATES: + NOTREACHED() << "Unexpected Auth error (" + << sync_service_->GetAuthError().state() + << "): " << sync_service_->GetAuthError().error_message(); + break; + } + if (sync_service_->HasUnrecoverableError()) + return kSyncServiceUnrecoverableError; + if (sync_service_->IsPassphraseRequiredForDecryption()) + return kSyncServiceNeedsPassphrase; + return kNoSyncServiceError; +} + +bool SyncSetupService::HasFinishedInitialSetup() { + // Sync initial setup is considered to finished iff: + // 1. User is signed in with sync enabled and the sync setup was completed. + // OR + // 2. User is not signed in or has disabled sync. + return !sync_service_->IsSyncEnabledAndLoggedIn() || + sync_service_->HasSyncSetupCompleted(); +} + +void SyncSetupService::PrepareForFirstSyncSetup() { + // |PrepareForFirstSyncSetup| should always be called while the user is signed + // out. At that time, sync setup is not completed. + DCHECK(!sync_service_->HasSyncSetupCompleted()); + sync_service_->SetSetupInProgress(true); +} + +void SyncSetupService::CommitChanges() { + if (sync_service_->FirstSetupInProgress()) { + // Turn on the sync setup completed flag only if the user did not turn sync + // off. + if (sync_service_->IsSyncEnabledAndLoggedIn()) { + sync_service_->SetSyncSetupCompleted(); + } + } + + sync_service_->SetSetupInProgress(false); +} + +bool SyncSetupService::HasUncommittedChanges() { + return sync_service_->setup_in_progress(); +} + +void SyncSetupService::SetSyncEnabledWithoutChangingDatatypes( + bool sync_enabled) { + sync_service_->SetSetupInProgress(true); + if (sync_enabled) + sync_service_->UnsuppressAndStart(); + else + sync_service_->StopAndSuppress(); +} diff --git a/ios/chrome/browser/sync/sync_setup_service.h b/ios/chrome/browser/sync/sync_setup_service.h new file mode 100644 index 0000000..491a09b --- /dev/null +++ b/ios/chrome/browser/sync/sync_setup_service.h @@ -0,0 +1,111 @@ +// Copyright 2012 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_SYNC_SYNC_SETUP_SERVICE_H_ +#define IOS_CHROME_BROWSER_SYNC_SYNC_SETUP_SERVICE_H_ + +#include <map> + +#include "base/basictypes.h" +#include "base/strings/string16.h" +#include "components/keyed_service/core/keyed_service.h" +#include "sync/internal_api/public/base/model_type.h" +#include "sync/internal_api/public/util/syncer_error.h" + +namespace sync_driver { +class SyncService; +} + +class PrefService; + +// Class that allows configuring sync. It handles enabling and disabling it, as +// well as choosing datatypes. Most actions are delayed until a commit is done, +// to allow the complex sync setup flow on iOS. +class SyncSetupService : public KeyedService { + public: + typedef enum { + kNoSyncServiceError, + kSyncServiceSignInNeedsUpdate, + kSyncServiceCouldNotConnect, + kSyncServiceServiceUnavailable, + kSyncServiceNeedsPassphrase, + kSyncServiceUnrecoverableError, + kLastSyncServiceError = kSyncServiceUnrecoverableError + } SyncServiceState; + + // The set of user-selectable datatypes handled by Chrome for iOS. + typedef enum { + kSyncBookmarks, + kSyncOmniboxHistory, + kSyncPasswords, + kSyncOpenTabs, + kSyncAutofill, + kNumberOfSyncableDatatypes + } SyncableDatatype; + + SyncSetupService(sync_driver::SyncService* sync_service, PrefService* prefs); + ~SyncSetupService() override; + + // Returns the |syncer::ModelType| associated to the given + // |SyncableDatatypes|. + syncer::ModelType GetModelType(SyncableDatatype datatype); + + // Returns whether sync is enabled. + virtual bool IsSyncEnabled() const; + // Enables or disables sync. Changes won't take effect in the sync backend + // before the next call to |CommitChanges|. + virtual void SetSyncEnabled(bool sync_enabled); + + // Returns all currently enabled datatypes. + syncer::ModelTypeSet GetDataTypes() const; + // Returns whether the given datatype is enabled. + virtual bool IsDataTypeEnabled(syncer::ModelType datatype) const; + // Enables or disables the given datatype. To be noted: this can be called at + // any time, but will only be meaningful if |IsSyncEnabled| is true and + // |IsSyncingAllDataTypes| is false. Changes won't take effect in the sync + // backend before the next call to |CommitChanges|. + void SetDataTypeEnabled(syncer::ModelType datatype, bool enabled); + + // Returns whether the user needs to enter a passphrase or enable sync to make + // sync work. + bool UserActionIsRequiredToHaveSyncWork(); + + // Returns whether all datatypes are being synced. + virtual bool IsSyncingAllDataTypes() const; + // Sets whether all datatypes should be synced or not. Changes won't take + // effect before the next call to |CommitChanges|. + virtual void SetSyncingAllDataTypes(bool sync_all); + + // Returns the current sync service state. + virtual SyncServiceState GetSyncServiceState(); + + // Returns true if the user has gone through the initial sync configuration. + // This method is guaranteed not to start the sync backend so it can be + // called at start-up. + bool HasFinishedInitialSetup(); + + // Pauses sync allowing the user to configure what data to sync before + // actually starting to sync data with the server. + void PrepareForFirstSyncSetup(); + + // Commit the current state of the configuration to the sync backend. + void CommitChanges(); + + // Returns true if there are uncommitted sync changes; + bool HasUncommittedChanges(); + + private: + // Enables or disables sync. Changes won't take effect in the sync backend + // before the next call to |CommitChanges|. No changes are made to the + // currently selected datatypes. + void SetSyncEnabledWithoutChangingDatatypes(bool sync_enabled); + + sync_driver::SyncService* const sync_service_; + PrefService* const prefs_; + syncer::ModelTypeSet user_selectable_types_; + + DISALLOW_COPY_AND_ASSIGN(SyncSetupService); +}; + +#endif // IOS_CHROME_BROWSER_SYNC_SYNC_SETUP_SERVICE_H_ diff --git a/ios/chrome/browser/sync/sync_setup_service_mock.cc b/ios/chrome/browser/sync/sync_setup_service_mock.cc new file mode 100644 index 0000000..39be8b7 --- /dev/null +++ b/ios/chrome/browser/sync/sync_setup_service_mock.cc @@ -0,0 +1,14 @@ +// Copyright 2013 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. + +#include "ios/chrome/browser/sync/sync_setup_service_mock.h" + +SyncSetupServiceMock::SyncSetupServiceMock( + sync_driver::SyncService* sync_service, + PrefService* prefs) + : SyncSetupService(sync_service, prefs) { +} + +SyncSetupServiceMock::~SyncSetupServiceMock() { +} diff --git a/ios/chrome/browser/sync/sync_setup_service_mock.h b/ios/chrome/browser/sync/sync_setup_service_mock.h new file mode 100644 index 0000000..aa2f8ea --- /dev/null +++ b/ios/chrome/browser/sync/sync_setup_service_mock.h @@ -0,0 +1,28 @@ +// Copyright 2013 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_SYNC_SYNC_SETUP_SERVICE_MOCK_H_ +#define IOS_CHROME_BROWSER_SYNC_SYNC_SETUP_SERVICE_MOCK_H_ + +#include "ios/chrome/browser/sync/sync_setup_service.h" + +#include "testing/gmock/include/gmock/gmock.h" + +// Mock for the class that allows configuring sync on iOS. +class SyncSetupServiceMock : public SyncSetupService { + public: + SyncSetupServiceMock(sync_driver::SyncService* sync_service, + PrefService* prefs); + ~SyncSetupServiceMock(); + + MOCK_CONST_METHOD0(IsSyncEnabled, bool()); + + MOCK_CONST_METHOD0(IsSyncingAllDataTypes, bool()); + + MOCK_METHOD0(GetSyncServiceState, SyncServiceState()); + + MOCK_CONST_METHOD1(IsDataTypeEnabled, bool(syncer::ModelType)); +}; + +#endif // IOS_CHROME_BROWSER_SYNC_SYNC_SETUP_SERVICE_MOCK_H_ |