summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorlipalani@chromium.org <lipalani@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-04 01:55:52 +0000
committerlipalani@chromium.org <lipalani@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-04 01:55:52 +0000
commitcb5199b4febc8e49b8fb4d858cbcb9fbb0d0eb25 (patch)
tree129987cb44caf890dd8d137fd8d675b010dc7266 /chrome/browser
parentf93a3ef6919cb7a9ade472a515df0789b44282bd (diff)
downloadchromium_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')
-rw-r--r--chrome/browser/sync/engine/all_status.cc6
-rw-r--r--chrome/browser/sync/engine/syncer_proto_util.cc116
-rw-r--r--chrome/browser/sync/glue/sync_backend_host.cc18
-rw-r--r--chrome/browser/sync/glue/sync_backend_host.h13
-rw-r--r--chrome/browser/sync/glue/sync_backend_host_unittest.cc3
-rw-r--r--chrome/browser/sync/internal_api/sync_manager.cc10
-rw-r--r--chrome/browser/sync/internal_api/sync_manager.h7
-rw-r--r--chrome/browser/sync/internal_api/syncapi_unittest.cc2
-rw-r--r--chrome/browser/sync/js/DEPS1
-rw-r--r--chrome/browser/sync/js/js_sync_manager_observer.cc13
-rw-r--r--chrome/browser/sync/js/js_sync_manager_observer.h3
-rw-r--r--chrome/browser/sync/js/js_sync_manager_observer_unittest.cc17
-rw-r--r--chrome/browser/sync/profile_sync_service.cc62
-rw-r--r--chrome/browser/sync/profile_sync_service.h13
-rw-r--r--chrome/browser/sync/profile_sync_service_mock.h3
-rw-r--r--chrome/browser/sync/sync_setup_flow.cc7
-rw-r--r--chrome/browser/sync/sync_setup_wizard.h4
-rw-r--r--chrome/browser/sync/sync_ui_util.cc85
-rw-r--r--chrome/browser/sync/test/engine/syncer_command_test.h3
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.