diff options
author | lipalani@chromium.org <lipalani@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-04 01:55:52 +0000 |
---|---|---|
committer | lipalani@chromium.org <lipalani@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-04 01:55:52 +0000 |
commit | cb5199b4febc8e49b8fb4d858cbcb9fbb0d0eb25 (patch) | |
tree | 129987cb44caf890dd8d137fd8d675b010dc7266 /chrome/browser | |
parent | f93a3ef6919cb7a9ade472a515df0789b44282bd (diff) | |
download | chromium_src-cb5199b4febc8e49b8fb4d858cbcb9fbb0d0eb25.zip chromium_src-cb5199b4febc8e49b8fb4d858cbcb9fbb0d0eb25.tar.gz chromium_src-cb5199b4febc8e49b8fb4d858cbcb9fbb0d0eb25.tar.bz2 |
Plug in legacy error code sent by the server to the new model by converting the error code to the new structure.
BUG=94007,70276
TEST=
Review URL: http://codereview.chromium.org/7740067
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@99583 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
19 files changed, 278 insertions, 108 deletions
diff --git a/chrome/browser/sync/engine/all_status.cc b/chrome/browser/sync/engine/all_status.cc index 1853a26..05b4f0f 100644 --- a/chrome/browser/sync/engine/all_status.cc +++ b/chrome/browser/sync/engine/all_status.cc @@ -69,6 +69,8 @@ sync_api::SyncManager::Status AllStatus::CalcSyncing( status.updates_available += snapshot->num_server_changes_remaining; + status.sync_protocol_error = snapshot->errors.sync_protocol_error; + // Accumulate update count only once per session to avoid double-counting. // TODO(ncarter): Make this realtime by having the syncer_status // counter preserve its value across sessions. http://crbug.com/26339 @@ -128,6 +130,10 @@ void AllStatus::OnSyncEngineEvent(const SyncEngineEvent& event) { case SyncEngineEvent::CLEAR_SERVER_DATA_FAILED: case SyncEngineEvent::CLEAR_SERVER_DATA_SUCCEEDED: break; + case SyncEngineEvent::ACTIONABLE_ERROR: + status_ = CreateBlankStatus(); + status_.sync_protocol_error = event.snapshot->errors.sync_protocol_error; + break; default: LOG(ERROR) << "Unrecognized Syncer Event: " << event.what_happened; break; diff --git a/chrome/browser/sync/engine/syncer_proto_util.cc b/chrome/browser/sync/engine/syncer_proto_util.cc index d0e120b..f382793 100644 --- a/chrome/browser/sync/engine/syncer_proto_util.cc +++ b/chrome/browser/sync/engine/syncer_proto_util.cc @@ -103,16 +103,6 @@ bool SyncerProtoUtil::VerifyResponseBirthday(syncable::Directory* dir, std::string local_birthday = dir->store_birthday(); - // TODO(lipalani) : Remove this check here. When the new implementation - // becomes the default this check should go away. This is handled by the - // switch case in the new implementation. - if (response->error_code() == ClientToServerResponse::CLEAR_PENDING || - response->error_code() == ClientToServerResponse::NOT_MY_BIRTHDAY) { - // Birthday verification failures result in stopping sync and deleting - // local sync data. - return false; - } - if (local_birthday.empty()) { if (!response->has_store_birthday()) { LOG(WARNING) << "Expected a birthday on first sync."; @@ -270,10 +260,21 @@ browser_sync::SyncProtocolError ConvertErrorPBToLocalType( sync_protocol_error.url = error.url(); sync_protocol_error.action = ConvertClientActionPBToLocalClientAction( error.action()); - return sync_protocol_error; } +// TODO(lipalani) : Rename these function names as per the CR for issue 7740067. +browser_sync::SyncProtocolError ConvertLegacyErrorCodeToNewError( + const sync_pb::ClientToServerResponse::ErrorType& error_type) { + browser_sync::SyncProtocolError error; + error.error_type = ConvertSyncProtocolErrorTypePBToLocalType(error_type); + if (error_type == ClientToServerResponse::CLEAR_PENDING || + error_type == ClientToServerResponse::NOT_MY_BIRTHDAY) { + error.action = browser_sync::DISABLE_SYNC_ON_CLIENT; + } // There is no other action we can compute for legacy server. + return error; +} + } // namespace // static @@ -297,85 +298,52 @@ bool SyncerProtoUtil::PostClientToServerMessage( msg, response)) return false; - if (response->has_error()) { - // We are talking to a server that is capable of sending the |error| tag. - browser_sync::SyncProtocolError sync_protocol_error = - ConvertErrorPBToLocalType(response->error()); - - // Birthday mismatch overrides any error that is sent by the server. - if (!VerifyResponseBirthday(dir, response)) { - sync_protocol_error.error_type = browser_sync::NOT_MY_BIRTHDAY; - sync_protocol_error.action = - browser_sync::DISABLE_SYNC_ON_CLIENT; - } - - // Now set the error into the status so the layers above us could read it. - sessions::StatusController* status = session->status_controller(); - status->set_sync_protocol_error(sync_protocol_error); - - // Inform the delegate of the error we got. - session->delegate()->OnSyncProtocolError(session->TakeSnapshot()); - - // Now do any special handling for the error type and decide on the return - // value. - switch (sync_protocol_error.error_type) { - case browser_sync::UNKNOWN_ERROR: - LOG(WARNING) << "Sync protocol out-of-date. The server is using a more " - << "recent version."; - return false; - case browser_sync::SYNC_SUCCESS: - LogResponseProfilingData(*response); - return true; - case browser_sync::THROTTLED: - LOG(WARNING) << "Client silenced by server."; - session->delegate()->OnSilencedUntil(base::TimeTicks::Now() + - GetThrottleDelay(*response)); - return false; - case browser_sync::TRANSIENT_ERROR: - return false; - case browser_sync::MIGRATION_DONE: - HandleMigrationDoneResponse(response, session); - return false; - default: - NOTREACHED(); - return false; - } - } + browser_sync::SyncProtocolError sync_protocol_error; - // TODO(lipalani): Plug this legacy implementation to the new error framework. - // New implementation code would have returned before by now. This is waiting - // on the frontend code being implemented. Otherwise ripping this would break - // sync. + // Birthday mismatch overrides any error that is sent by the server. if (!VerifyResponseBirthday(dir, response)) { - session->status_controller()->set_syncer_stuck(true); - session->delegate()->OnShouldStopSyncingPermanently(); - return false; + sync_protocol_error.error_type = browser_sync::NOT_MY_BIRTHDAY; + sync_protocol_error.action = + browser_sync::DISABLE_SYNC_ON_CLIENT; + } else if (response->has_error()) { + // This is a new server. Just get the error from the protocol. + sync_protocol_error = ConvertErrorPBToLocalType(response->error()); + } else { + // Legacy server implementation. Compute the error based on |error_code|. + sync_protocol_error = ConvertLegacyErrorCodeToNewError( + response->error_code()); } - switch (response->error_code()) { - case ClientToServerResponse::UNKNOWN: + // Now set the error into the status so the layers above us could read it. + sessions::StatusController* status = session->status_controller(); + status->set_sync_protocol_error(sync_protocol_error); + + // Inform the delegate of the error we got. + session->delegate()->OnSyncProtocolError(session->TakeSnapshot()); + + // Now do any special handling for the error type and decide on the return + // value. + switch (sync_protocol_error.error_type) { + case browser_sync::UNKNOWN_ERROR: LOG(WARNING) << "Sync protocol out-of-date. The server is using a more " << "recent version."; return false; - case ClientToServerResponse::SUCCESS: + case browser_sync::SYNC_SUCCESS: LogResponseProfilingData(*response); return true; - case ClientToServerResponse::THROTTLED: + case browser_sync::THROTTLED: LOG(WARNING) << "Client silenced by server."; session->delegate()->OnSilencedUntil(base::TimeTicks::Now() + GetThrottleDelay(*response)); return false; - case ClientToServerResponse::TRANSIENT_ERROR: + case browser_sync::TRANSIENT_ERROR: return false; - case ClientToServerResponse::MIGRATION_DONE: + case browser_sync::MIGRATION_DONE: HandleMigrationDoneResponse(response, session); return false; - case ClientToServerResponse::USER_NOT_ACTIVATED: - case ClientToServerResponse::AUTH_INVALID: - case ClientToServerResponse::ACCESS_DENIED: - // WARNING: PostAndProcessHeaders contains a hack for this case. - LOG(WARNING) << "SyncerProtoUtil: Authentication expired."; - // TODO(sync): Was this meant to be a fall-through? + case browser_sync::CLEAR_PENDING: + case browser_sync::NOT_MY_BIRTHDAY: + return false; default: NOTREACHED(); return false; diff --git a/chrome/browser/sync/glue/sync_backend_host.cc b/chrome/browser/sync/glue/sync_backend_host.cc index f8a1849..4c5afd0 100644 --- a/chrome/browser/sync/glue/sync_backend_host.cc +++ b/chrome/browser/sync/glue/sync_backend_host.cc @@ -758,6 +758,14 @@ void SyncBackendHost::Core::HandleSyncCycleCompletedOnFrontendLoop( host_->frontend_->OnSyncCycleCompleted(); } +void SyncBackendHost::Core::HandleActionableErrorEventOnFrontendLoop( + const browser_sync::SyncProtocolError& sync_error) { + DCHECK_EQ(MessageLoop::current(), host_->frontend_loop_); + if (!host_ || !host_->frontend_) + return; + host_->frontend_->OnActionableError(sync_error); +} + void SyncBackendHost::Core::OnInitializationComplete( const WeakHandle<JsBackend>& js_backend) { if (!host_ || !host_->frontend_) @@ -866,6 +874,16 @@ void SyncBackendHost::Core::OnEncryptionComplete( encrypted_types)); } +void SyncBackendHost::Core::OnActionableError( + const browser_sync::SyncProtocolError& sync_error) { + if (!host_ || !host_->frontend_) + return; + host_->frontend_loop_->PostTask( + FROM_HERE, + NewRunnableMethod(this, &Core::HandleActionableErrorEventOnFrontendLoop, + sync_error)); +} + void SyncBackendHost::Core::HandleStopSyncingPermanentlyOnFrontendLoop() { if (!host_ || !host_->frontend_) return; diff --git a/chrome/browser/sync/glue/sync_backend_host.h b/chrome/browser/sync/glue/sync_backend_host.h index c8b2d62..2f883e7 100644 --- a/chrome/browser/sync/glue/sync_backend_host.h +++ b/chrome/browser/sync/glue/sync_backend_host.h @@ -21,6 +21,7 @@ #include "chrome/browser/sync/internal_api/configure_reason.h" #include "chrome/browser/sync/internal_api/sync_manager.h" #include "chrome/browser/sync/notifier/sync_notifier_factory.h" +#include "chrome/browser/sync/protocol/sync_protocol_error.h" #include "chrome/browser/sync/syncable/model_type.h" #include "chrome/browser/sync/weak_handle.h" #include "chrome/common/net/gaia/google_service_auth_error.h" @@ -97,6 +98,10 @@ class SyncFrontend { // Inform the Frontend that new datatypes are available for registration. virtual void OnDataTypesChanged(const syncable::ModelTypeSet& to_add) = 0; + // Called when the sync cycle returns there is an user actionable error. + virtual void OnActionableError( + const browser_sync::SyncProtocolError& error) = 0; + protected: // Don't delete through SyncFrontend interface. virtual ~SyncFrontend() { @@ -275,7 +280,9 @@ class SyncBackendHost { virtual void OnClearServerDataFailed() OVERRIDE; virtual void OnClearServerDataSucceeded() OVERRIDE; virtual void OnEncryptionComplete( - const syncable::ModelTypeSet& encrypted_types) OVERRIDE; + const syncable::ModelTypeSet& encrypted_types); + virtual void OnActionableError( + const browser_sync::SyncProtocolError& sync_error); struct DoInitializeOptions { DoInitializeOptions( @@ -384,6 +391,10 @@ class SyncBackendHost { const WeakHandle<JsBackend>& js_backend, bool success); + // Let the front end handle the actionable error event. + void HandleActionableErrorEventOnFrontendLoop( + const browser_sync::SyncProtocolError& sync_error); + private: friend class base::RefCountedThreadSafe<SyncBackendHost::Core>; friend class SyncBackendHostForProfileSyncTest; diff --git a/chrome/browser/sync/glue/sync_backend_host_unittest.cc b/chrome/browser/sync/glue/sync_backend_host_unittest.cc index 3fedd46..a274909 100644 --- a/chrome/browser/sync/glue/sync_backend_host_unittest.cc +++ b/chrome/browser/sync/glue/sync_backend_host_unittest.cc @@ -9,6 +9,7 @@ #include "base/memory/scoped_ptr.h" #include "base/message_loop.h" #include "chrome/browser/sync/engine/model_safe_worker.h" +#include "chrome/browser/sync/protocol/sync_protocol_error.h" #include "chrome/browser/sync/syncable/model_type.h" #include "chrome/test/base/testing_profile.h" #include "chrome/test/base/test_url_request_context_getter.h" @@ -42,6 +43,8 @@ class MockSyncFrontend : public SyncFrontend { MOCK_METHOD1(OnEncryptionComplete, void(const syncable::ModelTypeSet&)); MOCK_METHOD1(OnMigrationNeededForTypes, void(const syncable::ModelTypeSet&)); MOCK_METHOD1(OnDataTypesChanged, void(const syncable::ModelTypeSet&)); + MOCK_METHOD1(OnActionableError, + void(const browser_sync::SyncProtocolError& sync_error)); }; } // namespace diff --git a/chrome/browser/sync/internal_api/sync_manager.cc b/chrome/browser/sync/internal_api/sync_manager.cc index 3669e68..6b022da 100644 --- a/chrome/browser/sync/internal_api/sync_manager.cc +++ b/chrome/browser/sync/internal_api/sync_manager.cc @@ -1692,6 +1692,16 @@ void SyncManager::SyncInternal::OnSyncEngineEvent( OnUpdatedToken(event.updated_token)); return; } + + if (event.what_happened == SyncEngineEvent::ACTIONABLE_ERROR) { + ObserverList<SyncManager::Observer> temp_obs_list; + CopyObservers(&temp_obs_list); + FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list, + OnActionableError( + event.snapshot->errors.sync_protocol_error)); + return; + } + } void SyncManager::SyncInternal::SetJsEventHandler( diff --git a/chrome/browser/sync/internal_api/sync_manager.h b/chrome/browser/sync/internal_api/sync_manager.h index 3f1f627..fdd9bbd 100644 --- a/chrome/browser/sync/internal_api/sync_manager.h +++ b/chrome/browser/sync/internal_api/sync_manager.h @@ -12,6 +12,7 @@ #include "base/memory/linked_ptr.h" #include "chrome/browser/sync/internal_api/configure_reason.h" #include "chrome/browser/sync/protocol/password_specifics.pb.h" +#include "chrome/browser/sync/protocol/sync_protocol_error.h" #include "chrome/browser/sync/syncable/model_type.h" #include "chrome/browser/sync/weak_handle.h" #include "chrome/common/net/gaia/google_service_auth_error.h" @@ -167,6 +168,8 @@ class SyncManager { // The max number of consecutive errors from any component. int max_consecutive_errors; + browser_sync::SyncProtocolError sync_protocol_error; + int unsynced_count; int conflicting_count; @@ -379,6 +382,10 @@ class SyncManager { virtual void OnEncryptionComplete( const syncable::ModelTypeSet& encrypted_types) = 0; + virtual void OnActionableError( + const browser_sync::SyncProtocolError& sync_protocol_error) + = 0; + protected: virtual ~Observer(); }; diff --git a/chrome/browser/sync/internal_api/syncapi_unittest.cc b/chrome/browser/sync/internal_api/syncapi_unittest.cc index 50e3a36..77a4490 100644 --- a/chrome/browser/sync/internal_api/syncapi_unittest.cc +++ b/chrome/browser/sync/internal_api/syncapi_unittest.cc @@ -708,6 +708,8 @@ class SyncManagerObserverMock : public SyncManager::Observer { MOCK_METHOD0(OnClearServerDataFailed, void()); // NOLINT MOCK_METHOD0(OnClearServerDataSucceeded, void()); // NOLINT MOCK_METHOD1(OnEncryptionComplete, void(const ModelTypeSet&)); // NOLINT + MOCK_METHOD1(OnActionableError, + void(const browser_sync::SyncProtocolError&)); // NOLINT }; class SyncNotifierMock : public sync_notifier::SyncNotifier { diff --git a/chrome/browser/sync/js/DEPS b/chrome/browser/sync/js/DEPS index 3a59572..45bf355 100644 --- a/chrome/browser/sync/js/DEPS +++ b/chrome/browser/sync/js/DEPS @@ -6,6 +6,7 @@ include_rules = [ "+chrome/browser/sync/internal_api", "+chrome/browser/sync/sessions/session_state.h", "+chrome/browser/sync/syncable/model_type.h", + "+chrome/browser/sync/protocol/sync_protocol_error.h", "+chrome/browser/sync/syncable/transaction_observer.h", "+chrome/browser/sync/test", diff --git a/chrome/browser/sync/js/js_sync_manager_observer.cc b/chrome/browser/sync/js/js_sync_manager_observer.cc index e966ad3..920c048 100644 --- a/chrome/browser/sync/js/js_sync_manager_observer.cc +++ b/chrome/browser/sync/js/js_sync_manager_observer.cc @@ -17,6 +17,8 @@ namespace browser_sync { +using browser_sync::SyncProtocolError; + JsSyncManagerObserver::JsSyncManagerObserver() {} JsSyncManagerObserver::~JsSyncManagerObserver() {} @@ -126,6 +128,17 @@ void JsSyncManagerObserver::OnMigrationNeededForTypes( JsEventDetails(&details)); } +void JsSyncManagerObserver::OnActionableError( + const SyncProtocolError& sync_error) { + if (!event_handler_.IsInitialized()) { + return; + } + DictionaryValue details; + details.Set("syncError", sync_error.ToValue()); + HandleJsEvent(FROM_HERE, "onActionableError", + JsEventDetails(&details)); +} + void JsSyncManagerObserver::OnInitializationComplete( const WeakHandle<JsBackend>& js_backend) { if (!event_handler_.IsInitialized()) { diff --git a/chrome/browser/sync/js/js_sync_manager_observer.h b/chrome/browser/sync/js/js_sync_manager_observer.h index a4b364a..0cda841 100644 --- a/chrome/browser/sync/js/js_sync_manager_observer.h +++ b/chrome/browser/sync/js/js_sync_manager_observer.h @@ -10,6 +10,7 @@ #include "base/basictypes.h" #include "chrome/browser/sync/internal_api/sync_manager.h" +#include "chrome/browser/sync/protocol/sync_protocol_error.h" #include "chrome/browser/sync/weak_handle.h" namespace tracked_objects { @@ -50,6 +51,8 @@ class JsSyncManagerObserver : public sync_api::SyncManager::Observer { virtual void OnClearServerDataSucceeded(); virtual void OnClearServerDataFailed(); virtual void OnMigrationNeededForTypes(const syncable::ModelTypeSet& types); + virtual void OnActionableError( + const browser_sync::SyncProtocolError& sync_protocol_error); private: void HandleJsEvent(const tracked_objects::Location& from_here, diff --git a/chrome/browser/sync/js/js_sync_manager_observer_unittest.cc b/chrome/browser/sync/js/js_sync_manager_observer_unittest.cc index 148091d..cb194a0 100644 --- a/chrome/browser/sync/js/js_sync_manager_observer_unittest.cc +++ b/chrome/browser/sync/js/js_sync_manager_observer_unittest.cc @@ -17,6 +17,7 @@ #include "chrome/browser/sync/js/js_arg_list.h" #include "chrome/browser/sync/js/js_event_details.h" #include "chrome/browser/sync/js/js_test_util.h" +#include "chrome/browser/sync/protocol/sync_protocol_error.h" #include "chrome/browser/sync/sessions/session_state.h" #include "chrome/browser/sync/syncable/model_type.h" #include "chrome/browser/sync/test/engine/test_user_share.h" @@ -122,6 +123,22 @@ TEST_F(JsSyncManagerObserverTest, OnSyncCycleCompleted) { PumpLoop(); } +TEST_F(JsSyncManagerObserverTest, OnActionableError) { + browser_sync::SyncProtocolError sync_error; + sync_error.action = browser_sync::CLEAR_USER_DATA_AND_RESYNC; + sync_error.error_type = browser_sync::TRANSIENT_ERROR; + DictionaryValue expected_details; + expected_details.Set("syncError", sync_error.ToValue()); + + EXPECT_CALL(mock_js_event_handler_, + HandleJsEvent("onActionableError", + HasDetailsAsDictionary(expected_details))); + + js_sync_manager_observer_.OnActionableError(sync_error); + PumpLoop(); +} + + TEST_F(JsSyncManagerObserverTest, OnAuthError) { GoogleServiceAuthError error(GoogleServiceAuthError::TWO_FACTOR); DictionaryValue expected_details; diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc index 0865dd7..ed9677f 100644 --- a/chrome/browser/sync/profile_sync_service.cc +++ b/chrome/browser/sync/profile_sync_service.cc @@ -65,6 +65,7 @@ using browser_sync::JsEventDetails; using browser_sync::JsEventHandler; using browser_sync::SyncBackendHost; using browser_sync::WeakHandle; +using browser_sync::SyncProtocolError; using sync_api::SyncCredentials; typedef GoogleServiceAuthError AuthError; @@ -77,6 +78,13 @@ const char* ProfileSyncService::kDevServerUrl = static const int kSyncClearDataTimeoutInSeconds = 60; // 1 minute. + +bool ShouldShowActionOnUI( + const browser_sync::SyncProtocolError& error) { + return (error.action != browser_sync::UNKNOWN_ACTION && + error.action != browser_sync::DISABLE_SYNC_ON_CLIENT); +} + ProfileSyncService::ProfileSyncService(ProfileSyncFactory* factory, Profile* profile, SigninManager* signin_manager, @@ -145,6 +153,7 @@ void ProfileSyncService::Initialize() { unrecoverable_error_detected_ = false; unrecoverable_error_message_.clear(); unrecoverable_error_location_.reset(); + last_actionable_error_ = SyncProtocolError(); // Watch the preference that indicates sync is managed so we can take // appropriate action. @@ -924,6 +933,35 @@ void ProfileSyncService::OnMigrationNeededForTypes( migrator_->MigrateTypes(types); } +void ProfileSyncService::OnActionableError(const SyncProtocolError& error) { + last_actionable_error_ = error; + DCHECK_NE(last_actionable_error_.action, + browser_sync::UNKNOWN_ACTION); + switch (error.action) { + case browser_sync::UPGRADE_CLIENT: + case browser_sync::CLEAR_USER_DATA_AND_RESYNC: + case browser_sync::ENABLE_SYNC_ON_ACCOUNT: + case browser_sync::STOP_AND_RESTART_SYNC: + // TODO(lipalani) : if setup in progress we want to display these + // actions in the popup. The current experience might not be optimal for + // the user. We just dismiss the dialog. + if (SetupInProgress()) { + wizard_.Step(SyncSetupWizard::ABORT); + OnStopSyncingPermanently(); + expect_sync_configuration_aborted_ = true; + } + // Trigger an unrecoverable error to stop syncing. + OnUnrecoverableError(FROM_HERE, last_actionable_error_.error_description); + break; + case browser_sync::DISABLE_SYNC_ON_CLIENT: + OnStopSyncingPermanently(); + break; + default: + NOTREACHED(); + } + NotifyObservers(); +} + void ProfileSyncService::ShowLoginDialog() { if (WizardIsVisible()) { wizard_.Focus(); @@ -939,7 +977,7 @@ void ProfileSyncService::ShowLoginDialog() { auth_error_time_ = base::TimeTicks(); // Reset auth_error_time_ to null. } - ShowSyncSetup(SyncSetupWizard::GetLoginState()); + ShowSyncSetupWithWizard(SyncSetupWizard::GetLoginState()); NotifyObservers(); } @@ -952,8 +990,10 @@ void ProfileSyncService::ShowErrorUI() { if (last_auth_error_.state() != AuthError::NONE) ShowLoginDialog(); + else if (ShouldShowActionOnUI(last_actionable_error_)) + ShowSyncSetup(chrome::kPersonalOptionsSubPage); else - ShowSyncSetup(SyncSetupWizard::NONFATAL_ERROR); + ShowSyncSetupWithWizard(SyncSetupWizard::NONFATAL_ERROR); } void ProfileSyncService::ShowConfigure(bool sync_everything) { @@ -963,23 +1003,28 @@ void ProfileSyncService::ShowConfigure(bool sync_everything) { } if (sync_everything) - ShowSyncSetup(SyncSetupWizard::SYNC_EVERYTHING); + ShowSyncSetupWithWizard(SyncSetupWizard::SYNC_EVERYTHING); else - ShowSyncSetup(SyncSetupWizard::CONFIGURE); + ShowSyncSetupWithWizard(SyncSetupWizard::CONFIGURE); } -void ProfileSyncService::ShowSyncSetup(SyncSetupWizard::State state) { - wizard_.Step(state); +void ProfileSyncService::ShowSyncSetup(const std::string& sub_page) { Browser* browser = BrowserList::GetLastActiveWithProfile(profile()); if (!browser) { browser = Browser::Create(profile()); - browser->ShowOptionsTab(chrome::kSyncSetupSubPage); + browser->ShowOptionsTab(sub_page); browser->window()->Show(); } else { - browser->ShowOptionsTab(chrome::kSyncSetupSubPage); + browser->ShowOptionsTab(sub_page); } } + +void ProfileSyncService::ShowSyncSetupWithWizard(SyncSetupWizard::State state) { + wizard_.Step(state); + ShowSyncSetup(chrome::kSyncSetupSubPage); +} + SyncBackendHost::StatusSummary ProfileSyncService::QuerySyncStatusSummary() { if (backend_.get() && backend_initialized_) return backend_->GetStatusSummary(); @@ -993,6 +1038,7 @@ SyncBackendHost::Status ProfileSyncService::QueryDetailedSyncStatus() { } else { SyncBackendHost::Status status; status.summary = SyncBackendHost::Status::OFFLINE_UNUSABLE; + status.sync_protocol_error = last_actionable_error_; return status; } } diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h index 00f71075..6b90e7b 100644 --- a/chrome/browser/sync/profile_sync_service.h +++ b/chrome/browser/sync/profile_sync_service.h @@ -209,6 +209,8 @@ class ProfileSyncService : public browser_sync::SyncFrontend, const syncable::ModelTypeSet& types) OVERRIDE; virtual void OnDataTypesChanged( const syncable::ModelTypeSet& to_add) OVERRIDE; + virtual void OnActionableError( + const browser_sync::SyncProtocolError& error) OVERRIDE; void OnClearServerDataTimeout(); @@ -266,7 +268,8 @@ class ProfileSyncService : public browser_sync::SyncFrontend, // types to sync. void ShowConfigure(bool sync_everything); - void ShowSyncSetup(SyncSetupWizard::State state); + void ShowSyncSetup(const std::string& sub_page); + void ShowSyncSetupWithWizard(SyncSetupWizard::State state); // Pretty-printed strings for a given StatusSummary. static std::string BuildSyncStatusSummaryText( @@ -660,7 +663,15 @@ class ProfileSyncService : public browser_sync::SyncFrontend, scoped_ptr<browser_sync::BackendMigrator> migrator_; + // This is the last |SyncProtocolError| we received from the server that had + // an action set on it. + browser_sync::SyncProtocolError last_actionable_error_; + DISALLOW_COPY_AND_ASSIGN(ProfileSyncService); }; +bool ShouldShowActionOnUI( + const browser_sync::SyncProtocolError& error); + + #endif // CHROME_BROWSER_SYNC_PROFILE_SYNC_SERVICE_H_ diff --git a/chrome/browser/sync/profile_sync_service_mock.h b/chrome/browser/sync/profile_sync_service_mock.h index 0c81c9c..54b094e 100644 --- a/chrome/browser/sync/profile_sync_service_mock.h +++ b/chrome/browser/sync/profile_sync_service_mock.h @@ -13,6 +13,7 @@ #include "chrome/browser/sync/glue/change_processor.h" #include "chrome/browser/sync/glue/data_type_controller.h" #include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/browser/sync/protocol/sync_protocol_error.h" #include "chrome/browser/sync/syncable/model_type.h" #include "testing/gmock/include/gmock/gmock.h" @@ -61,6 +62,8 @@ class ProfileSyncServiceMock : public ProfileSyncService { browser_sync::SyncBackendHost::Status()); MOCK_CONST_METHOD0(GetLastSyncedTimeString, string16()); MOCK_CONST_METHOD0(unrecoverable_error_detected, bool()); + MOCK_METHOD1(OnActionableError, void( + const browser_sync::SyncProtocolError&)); }; #endif // CHROME_BROWSER_SYNC_PROFILE_SYNC_SERVICE_MOCK_H_ diff --git a/chrome/browser/sync/sync_setup_flow.cc b/chrome/browser/sync/sync_setup_flow.cc index 9452217..a5d7ebf 100644 --- a/chrome/browser/sync/sync_setup_flow.cc +++ b/chrome/browser/sync/sync_setup_flow.cc @@ -362,14 +362,16 @@ bool SyncSetupFlow::ShouldAdvance(SyncSetupWizard::State state) { current_state_ == SyncSetupWizard::CONFIGURE || current_state_ == SyncSetupWizard::SETTING_UP; case SyncSetupWizard::SETUP_ABORTED_BY_PENDING_CLEAR: - return true; // The server can abort whenever it wants. + return current_state_ != SyncSetupWizard::ABORT; case SyncSetupWizard::SETTING_UP: return current_state_ == SyncSetupWizard::SYNC_EVERYTHING || current_state_ == SyncSetupWizard::CONFIGURE || current_state_ == SyncSetupWizard::ENTER_PASSPHRASE; case SyncSetupWizard::NONFATAL_ERROR: // Intentionally fall through. case SyncSetupWizard::FATAL_ERROR: - return true; // You can always hit the panic button. + return current_state_ != SyncSetupWizard::ABORT; + case SyncSetupWizard::ABORT: + return true; case SyncSetupWizard::DONE: return current_state_ == SyncSetupWizard::SETTING_UP || current_state_ == SyncSetupWizard::ENTER_PASSPHRASE; @@ -449,6 +451,7 @@ void SyncSetupFlow::ActivateState(SyncSetupWizard::State state) { break; } case SyncSetupWizard::DONE: + case SyncSetupWizard::ABORT: flow_handler_->ShowSetupDone( UTF16ToWide(service_->GetAuthenticatedUsername())); break; diff --git a/chrome/browser/sync/sync_setup_wizard.h b/chrome/browser/sync/sync_setup_wizard.h index 4b037cd..efaeff7 100644 --- a/chrome/browser/sync/sync_setup_wizard.h +++ b/chrome/browser/sync/sync_setup_wizard.h @@ -49,7 +49,9 @@ class SyncSetupWizard { // Loading screen with throbber. SETTING_UP, // A catch-all done case for any setup process. - DONE + DONE, + // Exit the wizard. + ABORT, }; explicit SyncSetupWizard(ProfileSyncService* service); diff --git a/chrome/browser/sync/sync_ui_util.cc b/chrome/browser/sync/sync_ui_util.cc index 188874d..0e6b6dd 100644 --- a/chrome/browser/sync/sync_ui_util.cc +++ b/chrome/browser/sync/sync_ui_util.cc @@ -85,6 +85,33 @@ string16 GetSyncedStateStatusLabel(ProfileSyncService* service) { service->GetLastSyncedTimeString()); } +void GetStatusForActionableError( + const browser_sync::SyncProtocolError& error, + string16* status_label) { + DCHECK(status_label); + switch (error.action) { + case browser_sync::STOP_AND_RESTART_SYNC: + status_label->assign( + l10n_util::GetStringUTF16(IDS_SYNC_STOP_AND_RESTART_SYNC)); + break; + case browser_sync::UPGRADE_CLIENT: + status_label->assign( + l10n_util::GetStringFUTF16(IDS_SYNC_UPGRADE_CLIENT, + l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))); + break; + case browser_sync::ENABLE_SYNC_ON_ACCOUNT: + status_label->assign( + l10n_util::GetStringUTF16(IDS_SYNC_ENABLE_SYNC_ON_ACCOUNT)); + break; + case browser_sync::CLEAR_USER_DATA_AND_RESYNC: + status_label->assign( + l10n_util::GetStringUTF16(IDS_SYNC_CLEAR_USER_DATA)); + break; + default: + NOTREACHED(); + } +} + // TODO(akalin): Write unit tests for these three functions below. // status_label and link_label must either be both NULL or both non-NULL. @@ -103,22 +130,40 @@ MessageType GetStatusInfo(ProfileSyncService* service, ProfileSyncService::Status status(service->QueryDetailedSyncStatus()); const AuthError& auth_error = service->GetAuthError(); - // Either show auth error information with a link to re-login, auth in prog, - // or note that everything is OK with the last synced time. - if (status.authenticated && !service->IsPassphraseRequired()) { - // Everything is peachy. - if (status_label) { - status_label->assign(GetSyncedStateStatusLabel(service)); - } - DCHECK_EQ(auth_error.state(), AuthError::NONE); - } else if (service->UIShouldDepictAuthInProgress()) { + // The order or priority is going to be: 1. Auth errors. 2. Protocol errors. + // 3. Passphrase errors. + + // For auth errors first check if an auth is in progress. + if (service->UIShouldDepictAuthInProgress()) { if (status_label) { status_label->assign( l10n_util::GetStringUTF16(IDS_SYNC_AUTHENTICATING_LABEL)); } - result_type = PRE_SYNCED; - } else if (service->IsPassphraseRequired()) { + return PRE_SYNCED; + } + + // No auth in progress check for an auth error. + if (auth_error.state() != AuthError::NONE) { + if (status_label && link_label) { + GetStatusLabelsForAuthError(auth_error, service, + status_label, link_label); + } + return SYNC_ERROR; + } + + // We dont have an auth error. Check for protocol error. + if (ShouldShowActionOnUI(status.sync_protocol_error)) { + if (status_label) { + GetStatusForActionableError(status.sync_protocol_error, + status_label); + } + return SYNC_ERROR; + } + + // Now finally passphrase error. + if (service->IsPassphraseRequired()) { if (service->IsPassphraseRequiredForDecryption()) { + // TODO(lipalani) : Ask tim if this is still needed. // NOT first machine. // Show a link ("needs attention"), but still indicate the // current synced status. Return SYNC_PROMO so that @@ -128,20 +173,16 @@ MessageType GetStatusInfo(ProfileSyncService* service, link_label->assign( l10n_util::GetStringUTF16(IDS_SYNC_PASSWORD_SYNC_ATTENTION)); } - result_type = SYNC_PROMO; + return SYNC_PROMO; } else { // First machine. Don't show promotion, just show everything // normal. if (status_label) status_label->assign(GetSyncedStateStatusLabel(service)); + return SYNCED; } - } else if (auth_error.state() != AuthError::NONE) { - if (status_label && link_label) { - GetStatusLabelsForAuthError(auth_error, service, - status_label, link_label); - } - result_type = SYNC_ERROR; } + return SYNCED; } else { // Either show auth error information with a link to re-login, auth in prog, // or provide a link to continue with setup. @@ -173,7 +214,13 @@ MessageType GetStatusInfo(ProfileSyncService* service, } } else if (service->unrecoverable_error_detected()) { result_type = SYNC_ERROR; - if (status_label) { + ProfileSyncService::Status status(service->QueryDetailedSyncStatus()); + if (ShouldShowActionOnUI(status.sync_protocol_error)) { + if (status_label) { + GetStatusForActionableError(status.sync_protocol_error, + status_label); + } + } else if (status_label) { status_label->assign(l10n_util::GetStringUTF16(IDS_SYNC_SETUP_ERROR)); } } diff --git a/chrome/browser/sync/test/engine/syncer_command_test.h b/chrome/browser/sync/test/engine/syncer_command_test.h index e153be23..ae9be64 100644 --- a/chrome/browser/sync/test/engine/syncer_command_test.h +++ b/chrome/browser/sync/test/engine/syncer_command_test.h @@ -38,7 +38,6 @@ class SyncerCommandTestWithParam : public testing::TestWithParam<T>, FAIL() << "Should not get silenced."; } virtual bool IsSyncingCurrentlySilenced() OVERRIDE { - ADD_FAILURE() << "No requests for silenced state should be made."; return false; } virtual void OnReceivedLongPollIntervalUpdate( @@ -58,7 +57,7 @@ class SyncerCommandTestWithParam : public testing::TestWithParam<T>, } virtual void OnSyncProtocolError( const sessions::SyncSessionSnapshot& session) OVERRIDE { - FAIL() << "Shouldn't be called."; + return; } // ModelSafeWorkerRegistrar implementation. |