summaryrefslogtreecommitdiffstats
path: root/sync
diff options
context:
space:
mode:
authorakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-18 20:50:28 +0000
committerakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-18 20:50:28 +0000
commit2d3d1d19828e0ad8ef5218a2cd7967079e13a1c8 (patch)
tree1469346ebe8cd33fe3c98aba590b53e6e90fb0ee /sync
parente341fb8781ffac9f1a6e166a2b304137508f58ff (diff)
downloadchromium_src-2d3d1d19828e0ad8ef5218a2cd7967079e13a1c8.zip
chromium_src-2d3d1d19828e0ad8ef5218a2cd7967079e13a1c8.tar.gz
chromium_src-2d3d1d19828e0ad8ef5218a2cd7967079e13a1c8.tar.bz2
[Sync] Propagate XMPP auth errors to SyncNotifierObservers
Detect XMPP auth errors and add new notifications to SingleLoginAttempt and Login. Replace PushClientObserver::OnNotificationStateChange with OnNotifications{Enabled,Disabled} notifications. Change SyncNotifierObserver similarly. Handle InvalidationClient errors and propagate auth errors from that, too. Propagate XMPP auth errors all the way up to SyncManager. It will be handled in a future CL. BUG=38091 TEST= Review URL: https://chromiumcodereview.appspot.com/10545170 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@142806 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sync')
-rw-r--r--sync/internal_api/public/engine/sync_status.h2
-rw-r--r--sync/internal_api/public/sync_manager.h5
-rw-r--r--sync/internal_api/sync_manager.cc66
-rw-r--r--sync/internal_api/syncapi_unittest.cc15
-rw-r--r--sync/notifier/chrome_invalidation_client.cc108
-rw-r--r--sync/notifier/chrome_invalidation_client.h32
-rw-r--r--sync/notifier/chrome_invalidation_client_unittest.cc86
-rw-r--r--sync/notifier/invalidation_notifier.cc17
-rw-r--r--sync/notifier/invalidation_notifier.h4
-rw-r--r--sync/notifier/invalidation_notifier_unittest.cc14
-rw-r--r--sync/notifier/mock_sync_notifier_observer.h3
-rw-r--r--sync/notifier/non_blocking_invalidation_notifier.cc51
-rw-r--r--sync/notifier/non_blocking_invalidation_notifier.h4
-rw-r--r--sync/notifier/non_blocking_invalidation_notifier_unittest.cc14
-rw-r--r--sync/notifier/notifications_disabled_reason.cc41
-rw-r--r--sync/notifier/notifications_disabled_reason.h33
-rw-r--r--sync/notifier/p2p_notifier.cc23
-rw-r--r--sync/notifier/p2p_notifier.h7
-rw-r--r--sync/notifier/p2p_notifier_unittest.cc8
-rw-r--r--sync/notifier/push_client_channel.cc14
-rw-r--r--sync/notifier/push_client_channel.h6
-rw-r--r--sync/notifier/push_client_channel_unittest.cc14
-rw-r--r--sync/notifier/sync_notifier_observer.h14
-rw-r--r--sync/sync.gyp2
-rw-r--r--sync/tools/sync_listen_notifications.cc15
25 files changed, 466 insertions, 132 deletions
diff --git a/sync/internal_api/public/engine/sync_status.h b/sync/internal_api/public/engine/sync_status.h
index 1c9ba1a..f05a5bc 100644
--- a/sync/internal_api/public/engine/sync_status.h
+++ b/sync/internal_api/public/engine/sync_status.h
@@ -22,6 +22,8 @@ struct SyncStatus {
SyncStatus();
~SyncStatus();
+ // TODO(akalin): Replace this with a NotificationsDisabledReason
+ // variable.
bool notifications_enabled; // True only if subscribed for notifications.
// Notifications counters updated by the actions in synapi.
diff --git a/sync/internal_api/public/sync_manager.h b/sync/internal_api/public/sync_manager.h
index f4a42e3..a03e2d7 100644
--- a/sync/internal_api/public/sync_manager.h
+++ b/sync/internal_api/public/sync_manager.h
@@ -532,8 +532,9 @@ class SyncManager {
// Functions used for testing.
- void TriggerOnNotificationStateChangeForTest(
- bool notifications_enabled);
+ void SimulateEnableNotificationsForTest();
+
+ void SimulateDisableNotificationsForTest(int reason);
void TriggerOnIncomingNotificationForTest(
syncable::ModelTypeSet model_types);
diff --git a/sync/internal_api/sync_manager.cc b/sync/internal_api/sync_manager.cc
index 8c95292..52a9c76 100644
--- a/sync/internal_api/sync_manager.cc
+++ b/sync/internal_api/sync_manager.cc
@@ -46,6 +46,7 @@
#include "sync/js/js_event_details.h"
#include "sync/js/js_event_handler.h"
#include "sync/js/js_reply_handler.h"
+#include "sync/notifier/notifications_disabled_reason.h"
#include "sync/notifier/sync_notifier.h"
#include "sync/notifier/sync_notifier_observer.h"
#include "sync/protocol/encryption.pb.h"
@@ -321,9 +322,9 @@ class SyncManager::SyncInternal
bool encrypt_everything) OVERRIDE;
// SyncNotifierObserver implementation.
- virtual void OnNotificationStateChange(
- bool notifications_enabled) OVERRIDE;
-
+ virtual void OnNotificationsEnabled() OVERRIDE;
+ virtual void OnNotificationsDisabled(
+ sync_notifier::NotificationsDisabledReason reason) OVERRIDE;
virtual void OnIncomingNotification(
const syncable::ModelTypePayloadMap& type_payloads,
sync_notifier::IncomingNotificationSource source) OVERRIDE;
@@ -2274,17 +2275,27 @@ void SyncManager::SyncInternal::OnEncryptedTypesChanged(
OnEncryptedTypesChanged(encrypted_types, encrypt_everything));
}
-void SyncManager::SyncInternal::OnNotificationStateChange(
- bool notifications_enabled) {
- DVLOG(1) << "P2P: Notifications enabled = "
- << (notifications_enabled ? "true" : "false");
- allstatus_.SetNotificationsEnabled(notifications_enabled);
+void SyncManager::SyncInternal::UpdateNotificationInfo(
+ const syncable::ModelTypePayloadMap& type_payloads) {
+ for (syncable::ModelTypePayloadMap::const_iterator it = type_payloads.begin();
+ it != type_payloads.end(); ++it) {
+ NotificationInfo* info = &notification_info_map_[it->first];
+ info->total_count++;
+ info->payload = it->second;
+ }
+}
+
+void SyncManager::SyncInternal::OnNotificationsEnabled() {
+ DVLOG(1) << "Notifications enabled";
+ allstatus_.SetNotificationsEnabled(true);
if (scheduler()) {
- scheduler()->set_notifications_enabled(notifications_enabled);
+ scheduler()->set_notifications_enabled(true);
}
+ // TODO(akalin): Separate onNotificationStateChange into
+ // enabled/disabled events.
if (js_event_handler_.IsInitialized()) {
DictionaryValue details;
- details.Set("enabled", Value::CreateBooleanValue(notifications_enabled));
+ details.Set("enabled", Value::CreateBooleanValue(true));
js_event_handler_.Call(FROM_HERE,
&JsEventHandler::HandleJsEvent,
"onNotificationStateChange",
@@ -2292,14 +2303,24 @@ void SyncManager::SyncInternal::OnNotificationStateChange(
}
}
-void SyncManager::SyncInternal::UpdateNotificationInfo(
- const syncable::ModelTypePayloadMap& type_payloads) {
- for (syncable::ModelTypePayloadMap::const_iterator it = type_payloads.begin();
- it != type_payloads.end(); ++it) {
- NotificationInfo* info = &notification_info_map_[it->first];
- info->total_count++;
- info->payload = it->second;
+void SyncManager::SyncInternal::OnNotificationsDisabled(
+ sync_notifier::NotificationsDisabledReason reason) {
+ DVLOG(1) << "Notifications disabled with reason "
+ << sync_notifier::NotificationsDisabledReasonToString(reason);
+ allstatus_.SetNotificationsEnabled(false);
+ if (scheduler()) {
+ scheduler()->set_notifications_enabled(false);
+ }
+ if (js_event_handler_.IsInitialized()) {
+ DictionaryValue details;
+ details.Set("enabled", Value::CreateBooleanValue(false));
+ js_event_handler_.Call(FROM_HERE,
+ &JsEventHandler::HandleJsEvent,
+ "onNotificationStateChange",
+ JsEventDetails(&details));
}
+ // TODO(akalin): Treat a CREDENTIALS_REJECTED state as an auth
+ // error.
}
void SyncManager::SyncInternal::OnIncomingNotification(
@@ -2422,10 +2443,15 @@ bool SyncManager::HasUnsyncedItems() const {
return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0);
}
-void SyncManager::TriggerOnNotificationStateChangeForTest(
- bool notifications_enabled) {
+void SyncManager::SimulateEnableNotificationsForTest() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ data_->OnNotificationsEnabled();
+}
+
+void SyncManager::SimulateDisableNotificationsForTest(int reason) {
DCHECK(thread_checker_.CalledOnValidThread());
- data_->OnNotificationStateChange(notifications_enabled);
+ data_->OnNotificationsDisabled(
+ static_cast<sync_notifier::NotificationsDisabledReason>(reason));
}
void SyncManager::TriggerOnIncomingNotificationForTest(
diff --git a/sync/internal_api/syncapi_unittest.cc b/sync/internal_api/syncapi_unittest.cc
index 1f1079c..460ee92 100644
--- a/sync/internal_api/syncapi_unittest.cc
+++ b/sync/internal_api/syncapi_unittest.cc
@@ -1275,16 +1275,19 @@ TEST_F(SyncManagerTest, OnNotificationStateChange) {
HandleJsEvent("onNotificationStateChange",
HasDetailsAsDictionary(false_details)));
- sync_manager_.TriggerOnNotificationStateChangeForTest(true);
- sync_manager_.TriggerOnNotificationStateChangeForTest(false);
+ sync_manager_.SimulateEnableNotificationsForTest();
+ sync_manager_.SimulateDisableNotificationsForTest(
+ sync_notifier::TRANSIENT_NOTIFICATION_ERROR);
SetJsEventHandler(event_handler.AsWeakHandle());
- sync_manager_.TriggerOnNotificationStateChangeForTest(true);
- sync_manager_.TriggerOnNotificationStateChangeForTest(false);
+ sync_manager_.SimulateEnableNotificationsForTest();
+ sync_manager_.SimulateDisableNotificationsForTest(
+ sync_notifier::TRANSIENT_NOTIFICATION_ERROR);
SetJsEventHandler(WeakHandle<JsEventHandler>());
- sync_manager_.TriggerOnNotificationStateChangeForTest(true);
- sync_manager_.TriggerOnNotificationStateChangeForTest(false);
+ sync_manager_.SimulateEnableNotificationsForTest();
+ sync_manager_.SimulateDisableNotificationsForTest(
+ sync_notifier::TRANSIENT_NOTIFICATION_ERROR);
// Should trigger the replies.
PumpLoop();
diff --git a/sync/notifier/chrome_invalidation_client.cc b/sync/notifier/chrome_invalidation_client.cc
index 278076f..030d7e5 100644
--- a/sync/notifier/chrome_invalidation_client.cc
+++ b/sync/notifier/chrome_invalidation_client.cc
@@ -31,15 +31,19 @@ ChromeInvalidationClient::Listener::~Listener() {}
ChromeInvalidationClient::ChromeInvalidationClient(
scoped_ptr<notifier::PushClient> push_client)
- : chrome_system_resources_(push_client.Pass(),
+ : push_client_(push_client.get()),
+ chrome_system_resources_(push_client.Pass(),
ALLOW_THIS_IN_INITIALIZER_LIST(this)),
listener_(NULL),
- ticl_ready_(false) {
+ ticl_state_(DEFAULT_NOTIFICATION_ERROR),
+ push_client_state_(DEFAULT_NOTIFICATION_ERROR) {
DCHECK(CalledOnValidThread());
+ push_client_->AddObserver(this);
}
ChromeInvalidationClient::~ChromeInvalidationClient() {
DCHECK(CalledOnValidThread());
+ push_client_->RemoveObserver(this);
Stop();
DCHECK(!listener_);
}
@@ -98,27 +102,10 @@ void ChromeInvalidationClient::UpdateCredentials(
chrome_system_resources_.network()->UpdateCredentials(email, token);
}
-void ChromeInvalidationClient::Stop() {
- DCHECK(CalledOnValidThread());
- if (!invalidation_client_.get()) {
- return;
- }
-
- registration_manager_.reset();
- chrome_system_resources_.Stop();
- invalidation_client_->Stop();
-
- invalidation_client_.reset();
- listener_ = NULL;
-
- invalidation_state_tracker_.Reset();
- max_invalidation_versions_.clear();
-}
-
void ChromeInvalidationClient::RegisterTypes(syncable::ModelTypeSet types) {
DCHECK(CalledOnValidThread());
registered_types_ = types;
- if (ticl_ready_ && registration_manager_.get()) {
+ if (GetState() == NO_NOTIFICATION_ERROR && registration_manager_.get()) {
registration_manager_->SetRegisteredTypes(registered_types_);
}
// TODO(akalin): Clear invalidation versions for unregistered types.
@@ -126,8 +113,8 @@ void ChromeInvalidationClient::RegisterTypes(syncable::ModelTypeSet types) {
void ChromeInvalidationClient::Ready(
invalidation::InvalidationClient* client) {
- ticl_ready_ = true;
- listener_->OnSessionStatusChanged(true);
+ ticl_state_ = NO_NOTIFICATION_ERROR;
+ EmitStateChange();
registration_manager_->SetRegisteredTypes(registered_types_);
}
@@ -286,9 +273,15 @@ void ChromeInvalidationClient::ReissueRegistrations(
void ChromeInvalidationClient::InformError(
invalidation::InvalidationClient* client,
const invalidation::ErrorInfo& error_info) {
- listener_->OnSessionStatusChanged(false);
- LOG(ERROR) << "Invalidation client encountered an error";
- // TODO(ghc): handle the error.
+ LOG(ERROR) << "Ticl error " << error_info.error_reason() << ": "
+ << error_info.error_message()
+ << " (transient = " << error_info.is_transient() << ")";
+ if (error_info.error_reason() == invalidation::ErrorReason::AUTH_FAILURE) {
+ ticl_state_ = NOTIFICATION_CREDENTIALS_REJECTED;
+ } else {
+ ticl_state_ = TRANSIENT_NOTIFICATION_ERROR;
+ }
+ EmitStateChange();
}
void ChromeInvalidationClient::WriteState(const std::string& state) {
@@ -298,4 +291,69 @@ void ChromeInvalidationClient::WriteState(const std::string& state) {
FROM_HERE, &InvalidationStateTracker::SetInvalidationState, state);
}
+void ChromeInvalidationClient::Stop() {
+ DCHECK(CalledOnValidThread());
+ if (!invalidation_client_.get()) {
+ return;
+ }
+
+ registration_manager_.reset();
+ chrome_system_resources_.Stop();
+ invalidation_client_->Stop();
+
+ invalidation_client_.reset();
+ listener_ = NULL;
+
+ invalidation_state_tracker_.Reset();
+ max_invalidation_versions_.clear();
+ ticl_state_ = DEFAULT_NOTIFICATION_ERROR;
+ push_client_state_ = DEFAULT_NOTIFICATION_ERROR;
+}
+
+NotificationsDisabledReason ChromeInvalidationClient::GetState() const {
+ DCHECK(CalledOnValidThread());
+ if (ticl_state_ == NOTIFICATION_CREDENTIALS_REJECTED ||
+ push_client_state_ == NOTIFICATION_CREDENTIALS_REJECTED) {
+ // If either the ticl or the push client rejected our credentials,
+ // return NOTIFICATION_CREDENTIALS_REJECTED.
+ return NOTIFICATION_CREDENTIALS_REJECTED;
+ }
+ if (ticl_state_ == NO_NOTIFICATION_ERROR &&
+ push_client_state_ == NO_NOTIFICATION_ERROR) {
+ // If the ticl is ready and the push client notifications are
+ // enabled, return NO_NOTIFICATION_ERROR.
+ return NO_NOTIFICATION_ERROR;
+ }
+ // Otherwise, we have a transient error.
+ return TRANSIENT_NOTIFICATION_ERROR;
+}
+
+void ChromeInvalidationClient::EmitStateChange() {
+ DCHECK(CalledOnValidThread());
+ if (GetState() == NO_NOTIFICATION_ERROR) {
+ listener_->OnNotificationsEnabled();
+ } else {
+ listener_->OnNotificationsDisabled(GetState());
+ }
+}
+
+void ChromeInvalidationClient::OnNotificationsEnabled() {
+ DCHECK(CalledOnValidThread());
+ push_client_state_ = NO_NOTIFICATION_ERROR;
+ EmitStateChange();
+}
+
+void ChromeInvalidationClient::OnNotificationsDisabled(
+ notifier::NotificationsDisabledReason reason) {
+ DCHECK(CalledOnValidThread());
+ push_client_state_ = FromNotifierReason(reason);
+ EmitStateChange();
+}
+
+void ChromeInvalidationClient::OnIncomingNotification(
+ const notifier::Notification& notification) {
+ DCHECK(CalledOnValidThread());
+ // Do nothing, since this is already handled by |invalidation_client_|.
+}
+
} // namespace sync_notifier
diff --git a/sync/notifier/chrome_invalidation_client.h b/sync/notifier/chrome_invalidation_client.h
index fe25dc3..c423c8d 100644
--- a/sync/notifier/chrome_invalidation_client.h
+++ b/sync/notifier/chrome_invalidation_client.h
@@ -17,11 +17,13 @@
#include "base/memory/weak_ptr.h"
#include "base/threading/non_thread_safe.h"
#include "google/cacheinvalidation/include/invalidation-listener.h"
+#include "jingle/notifier/listener/push_client_observer.h"
#include "sync/internal_api/public/syncable/model_type.h"
#include "sync/internal_api/public/syncable/model_type_payload_map.h"
#include "sync/internal_api/public/util/weak_handle.h"
#include "sync/notifier/chrome_system_resources.h"
#include "sync/notifier/invalidation_state_tracker.h"
+#include "sync/notifier/notifications_disabled_reason.h"
#include "sync/notifier/state_writer.h"
namespace buzz {
@@ -43,6 +45,7 @@ class RegistrationManager;
class ChromeInvalidationClient
: public InvalidationListener,
public StateWriter,
+ public notifier::PushClientObserver,
public base::NonThreadSafe {
public:
class Listener {
@@ -52,7 +55,10 @@ class ChromeInvalidationClient
virtual void OnInvalidate(
const syncable::ModelTypePayloadMap& type_payloads) = 0;
- virtual void OnSessionStatusChanged(bool has_session) = 0;
+ virtual void OnNotificationsEnabled() = 0;
+
+ virtual void OnNotificationsDisabled(
+ NotificationsDisabledReason reason) = 0;
};
explicit ChromeInvalidationClient(
@@ -77,8 +83,6 @@ class ChromeInvalidationClient
// notifications for. May be called at any time.
void RegisterTypes(syncable::ModelTypeSet types);
- virtual void WriteState(const std::string& state) OVERRIDE;
-
// invalidation::InvalidationListener implementation.
virtual void Ready(
invalidation::InvalidationClient* client) OVERRIDE;
@@ -110,14 +114,30 @@ class ChromeInvalidationClient
invalidation::InvalidationClient* client,
const invalidation::ErrorInfo& error_info) OVERRIDE;
+ // StateWriter implementation.
+ virtual void WriteState(const std::string& state) OVERRIDE;
+
+ // notifier::PushClientObserver implementation.
+ virtual void OnNotificationsEnabled() OVERRIDE;
+ virtual void OnNotificationsDisabled(
+ notifier::NotificationsDisabledReason reason) OVERRIDE;
+ virtual void OnIncomingNotification(
+ const notifier::Notification& notification) OVERRIDE;
+
private:
friend class ChromeInvalidationClientTest;
void Stop();
+ NotificationsDisabledReason GetState() const;
+
+ void EmitStateChange();
+
void EmitInvalidation(
syncable::ModelTypeSet types, const std::string& payload);
+ // Owned by |chrome_system_resources_|.
+ notifier::PushClient* const push_client_;
ChromeSystemResources chrome_system_resources_;
InvalidationVersionMap max_invalidation_versions_;
browser_sync::WeakHandle<InvalidationStateTracker>
@@ -127,7 +147,11 @@ class ChromeInvalidationClient
scoped_ptr<RegistrationManager> registration_manager_;
// Stored to pass to |registration_manager_| on start.
syncable::ModelTypeSet registered_types_;
- bool ticl_ready_;
+
+ // The states of the ticl and the push client (with
+ // NO_NOTIFICATION_ERROR meaning notifications are enabled).
+ NotificationsDisabledReason ticl_state_;
+ NotificationsDisabledReason push_client_state_;
DISALLOW_COPY_AND_ASSIGN(ChromeInvalidationClient);
};
diff --git a/sync/notifier/chrome_invalidation_client_unittest.cc b/sync/notifier/chrome_invalidation_client_unittest.cc
index f1470ac..7fa94ff 100644
--- a/sync/notifier/chrome_invalidation_client_unittest.cc
+++ b/sync/notifier/chrome_invalidation_client_unittest.cc
@@ -20,6 +20,7 @@
namespace sync_notifier {
using ::testing::_;
+using ::testing::InSequence;
using ::testing::Return;
using ::testing::StrictMock;
@@ -44,7 +45,8 @@ class MockInvalidationClient : public invalidation::InvalidationClient {
class MockListener : public ChromeInvalidationClient::Listener {
public:
MOCK_METHOD1(OnInvalidate, void(const syncable::ModelTypePayloadMap&));
- MOCK_METHOD1(OnSessionStatusChanged, void(bool));
+ MOCK_METHOD0(OnNotificationsEnabled, void());
+ MOCK_METHOD1(OnNotificationsDisabled, void(NotificationsDisabledReason));
};
} // namespace
@@ -52,9 +54,8 @@ class MockListener : public ChromeInvalidationClient::Listener {
class ChromeInvalidationClientTest : public testing::Test {
protected:
ChromeInvalidationClientTest()
- : client_(
- scoped_ptr<notifier::PushClient>(
- new notifier::FakePushClient())) {}
+ : fake_push_client_(new notifier::FakePushClient()),
+ client_(scoped_ptr<notifier::PushClient>(fake_push_client_)) {}
virtual void SetUp() {
client_.Start(kClientId, kClientInfo, kState,
@@ -116,6 +117,7 @@ class ChromeInvalidationClientTest : public testing::Test {
StrictMock<MockInvalidationStateTracker>
mock_invalidation_state_tracker_;
StrictMock<MockInvalidationClient> mock_invalidation_client_;
+ notifier::FakePushClient* const fake_push_client_;
ChromeInvalidationClient client_;
};
@@ -159,12 +161,6 @@ TEST_F(ChromeInvalidationClientTest, InvalidateWithPayload) {
FireInvalidate("PREFERENCE", 1, "payload");
}
-TEST_F(ChromeInvalidationClientTest, WriteState) {
- EXPECT_CALL(mock_invalidation_state_tracker_,
- SetInvalidationState(kNewState));
- client_.WriteState(kNewState);
-}
-
TEST_F(ChromeInvalidationClientTest, InvalidateVersion) {
using ::testing::Mock;
@@ -266,6 +262,74 @@ TEST_F(ChromeInvalidationClientTest, RegisterTypes) {
FireInvalidateAll();
}
-// TODO(akalin): Flesh out unit tests.
+TEST_F(ChromeInvalidationClientTest, WriteState) {
+ EXPECT_CALL(mock_invalidation_state_tracker_,
+ SetInvalidationState(kNewState));
+ client_.WriteState(kNewState);
+}
+
+TEST_F(ChromeInvalidationClientTest, StateChangesNotReady) {
+ InSequence dummy;
+ EXPECT_CALL(mock_listener_,
+ OnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR));
+ EXPECT_CALL(mock_listener_,
+ OnNotificationsDisabled(NOTIFICATION_CREDENTIALS_REJECTED));
+ EXPECT_CALL(mock_listener_,
+ OnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR));
+
+ fake_push_client_->DisableNotifications(
+ notifier::TRANSIENT_NOTIFICATION_ERROR);
+ fake_push_client_->DisableNotifications(
+ notifier::NOTIFICATION_CREDENTIALS_REJECTED);
+ fake_push_client_->EnableNotifications();
+}
+
+TEST_F(ChromeInvalidationClientTest, StateChangesReady) {
+ InSequence dummy;
+ EXPECT_CALL(mock_listener_,
+ OnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR));
+ EXPECT_CALL(mock_listener_, OnNotificationsEnabled());
+ EXPECT_CALL(mock_listener_,
+ OnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR));
+ EXPECT_CALL(mock_listener_,
+ OnNotificationsDisabled(NOTIFICATION_CREDENTIALS_REJECTED));
+ EXPECT_CALL(mock_listener_, OnNotificationsEnabled());
+
+ fake_push_client_->EnableNotifications();
+ client_.Ready(NULL);
+ fake_push_client_->DisableNotifications(
+ notifier::TRANSIENT_NOTIFICATION_ERROR);
+ fake_push_client_->DisableNotifications(
+ notifier::NOTIFICATION_CREDENTIALS_REJECTED);
+ fake_push_client_->EnableNotifications();
+}
+
+TEST_F(ChromeInvalidationClientTest, StateChangesAuthError) {
+ InSequence dummy;
+ EXPECT_CALL(mock_listener_,
+ OnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR));
+ EXPECT_CALL(mock_listener_, OnNotificationsEnabled());
+ EXPECT_CALL(mock_listener_,
+ OnNotificationsDisabled(NOTIFICATION_CREDENTIALS_REJECTED))
+ .Times(4);
+ EXPECT_CALL(mock_listener_, OnNotificationsEnabled());
+
+ fake_push_client_->EnableNotifications();
+ client_.Ready(NULL);
+
+ client_.InformError(
+ NULL,
+ invalidation::ErrorInfo(
+ invalidation::ErrorReason::AUTH_FAILURE,
+ false /* is_transient */,
+ "auth error",
+ invalidation::ErrorContext()));
+ fake_push_client_->DisableNotifications(
+ notifier::TRANSIENT_NOTIFICATION_ERROR);
+ fake_push_client_->DisableNotifications(
+ notifier::NOTIFICATION_CREDENTIALS_REJECTED);
+ fake_push_client_->EnableNotifications();
+ client_.Ready(NULL);
+}
} // namespace sync_notifier
diff --git a/sync/notifier/invalidation_notifier.cc b/sync/notifier/invalidation_notifier.cc
index 485e969..9925041 100644
--- a/sync/notifier/invalidation_notifier.cc
+++ b/sync/notifier/invalidation_notifier.cc
@@ -102,14 +102,23 @@ void InvalidationNotifier::SendNotification(
void InvalidationNotifier::OnInvalidate(
const syncable::ModelTypePayloadMap& type_payloads) {
DCHECK(CalledOnValidThread());
+ FOR_EACH_OBSERVER(
+ SyncNotifierObserver, observers_,
+ OnIncomingNotification(type_payloads,
+ sync_notifier::REMOTE_NOTIFICATION));
+}
+
+void InvalidationNotifier::OnNotificationsEnabled() {
+ DCHECK(CalledOnValidThread());
FOR_EACH_OBSERVER(SyncNotifierObserver, observers_,
- OnIncomingNotification(type_payloads,
- sync_notifier::REMOTE_NOTIFICATION));
+ OnNotificationsEnabled());
}
-void InvalidationNotifier::OnSessionStatusChanged(bool has_session) {
+void InvalidationNotifier::OnNotificationsDisabled(
+ NotificationsDisabledReason reason) {
+ DCHECK(CalledOnValidThread());
FOR_EACH_OBSERVER(SyncNotifierObserver, observers_,
- OnNotificationStateChange(has_session));
+ OnNotificationsDisabled(reason));
}
} // namespace sync_notifier
diff --git a/sync/notifier/invalidation_notifier.h b/sync/notifier/invalidation_notifier.h
index 4ac715e..5441094 100644
--- a/sync/notifier/invalidation_notifier.h
+++ b/sync/notifier/invalidation_notifier.h
@@ -64,7 +64,9 @@ class InvalidationNotifier
// ChromeInvalidationClient::Listener implementation.
virtual void OnInvalidate(
const syncable::ModelTypePayloadMap& type_payloads) OVERRIDE;
- virtual void OnSessionStatusChanged(bool has_session) OVERRIDE;
+ virtual void OnNotificationsEnabled() OVERRIDE;
+ virtual void OnNotificationsDisabled(
+ NotificationsDisabledReason reason) OVERRIDE;
private:
// We start off in the STOPPED state. When we get our initial
diff --git a/sync/notifier/invalidation_notifier_unittest.cc b/sync/notifier/invalidation_notifier_unittest.cc
index 16b70c1..9bd1840 100644
--- a/sync/notifier/invalidation_notifier_unittest.cc
+++ b/sync/notifier/invalidation_notifier_unittest.cc
@@ -80,11 +80,14 @@ TEST_F(InvalidationNotifierTest, Basic) {
type_payloads[syncable::BOOKMARKS] = "";
type_payloads[syncable::AUTOFILL] = "";
- EXPECT_CALL(mock_observer_, OnNotificationStateChange(true));
+ EXPECT_CALL(mock_observer_, OnNotificationsEnabled());
EXPECT_CALL(mock_observer_,
OnIncomingNotification(type_payloads,
REMOTE_NOTIFICATION));
- EXPECT_CALL(mock_observer_, OnNotificationStateChange(false));
+ EXPECT_CALL(mock_observer_,
+ OnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR));
+ EXPECT_CALL(mock_observer_,
+ OnNotificationsDisabled(NOTIFICATION_CREDENTIALS_REJECTED));
// Note no expectation on mock_tracker_, as we initialized with
// non-empty initial_invalidation_state above.
@@ -94,11 +97,14 @@ TEST_F(InvalidationNotifierTest, Basic) {
invalidation_notifier_->SetUniqueId("fake_id");
invalidation_notifier_->UpdateCredentials("foo@bar.com", "fake_token");
- invalidation_notifier_->OnSessionStatusChanged(true);
+ invalidation_notifier_->OnNotificationsEnabled();
invalidation_notifier_->OnInvalidate(type_payloads);
- invalidation_notifier_->OnSessionStatusChanged(false);
+ invalidation_notifier_->OnNotificationsDisabled(
+ TRANSIENT_NOTIFICATION_ERROR);
+ invalidation_notifier_->OnNotificationsDisabled(
+ NOTIFICATION_CREDENTIALS_REJECTED);
}
TEST_F(InvalidationNotifierTest, MigrateState) {
diff --git a/sync/notifier/mock_sync_notifier_observer.h b/sync/notifier/mock_sync_notifier_observer.h
index 426f065..95a5f06 100644
--- a/sync/notifier/mock_sync_notifier_observer.h
+++ b/sync/notifier/mock_sync_notifier_observer.h
@@ -18,10 +18,11 @@ class MockSyncNotifierObserver : public SyncNotifierObserver {
MockSyncNotifierObserver();
virtual ~MockSyncNotifierObserver();
+ MOCK_METHOD0(OnNotificationsEnabled, void());
+ MOCK_METHOD1(OnNotificationsDisabled, void(NotificationsDisabledReason));
MOCK_METHOD2(OnIncomingNotification,
void(const syncable::ModelTypePayloadMap&,
IncomingNotificationSource));
- MOCK_METHOD1(OnNotificationStateChange, void(bool));
};
} // namespace sync_notifier
diff --git a/sync/notifier/non_blocking_invalidation_notifier.cc b/sync/notifier/non_blocking_invalidation_notifier.cc
index f9a7bd1..a92bd66 100644
--- a/sync/notifier/non_blocking_invalidation_notifier.cc
+++ b/sync/notifier/non_blocking_invalidation_notifier.cc
@@ -42,10 +42,12 @@ class NonBlockingInvalidationNotifier::Core
// SyncNotifierObserver implementation (all called on I/O thread by
// InvalidationNotifier).
+ virtual void OnNotificationsEnabled() OVERRIDE;
+ virtual void OnNotificationsDisabled(
+ NotificationsDisabledReason reason) OVERRIDE;
virtual void OnIncomingNotification(
const syncable::ModelTypePayloadMap& type_payloads,
- IncomingNotificationSource source);
- virtual void OnNotificationStateChange(bool notifications_enabled);
+ IncomingNotificationSource source) OVERRIDE;
private:
friend class
@@ -126,22 +128,27 @@ void NonBlockingInvalidationNotifier::Core::UpdateEnabledTypes(
invalidation_notifier_->UpdateEnabledTypes(enabled_types);
}
-void NonBlockingInvalidationNotifier::Core::OnIncomingNotification(
- const syncable::ModelTypePayloadMap& type_payloads,
- IncomingNotificationSource source) {
+void NonBlockingInvalidationNotifier::Core::OnNotificationsEnabled() {
DCHECK(network_task_runner_->BelongsToCurrentThread());
delegate_observer_.Call(FROM_HERE,
- &SyncNotifierObserver::OnIncomingNotification,
- type_payloads,
- source);
+ &SyncNotifierObserver::OnNotificationsEnabled);
}
-void NonBlockingInvalidationNotifier::Core::OnNotificationStateChange(
- bool notifications_enabled) {
+void NonBlockingInvalidationNotifier::Core::OnNotificationsDisabled(
+ NotificationsDisabledReason reason) {
+ DCHECK(network_task_runner_->BelongsToCurrentThread());
+ delegate_observer_.Call(
+ FROM_HERE, &SyncNotifierObserver::OnNotificationsDisabled, reason);
+}
+
+void NonBlockingInvalidationNotifier::Core::OnIncomingNotification(
+ const syncable::ModelTypePayloadMap& type_payloads,
+ IncomingNotificationSource source) {
DCHECK(network_task_runner_->BelongsToCurrentThread());
delegate_observer_.Call(FROM_HERE,
- &SyncNotifierObserver::OnNotificationStateChange,
- notifications_enabled);
+ &SyncNotifierObserver::OnIncomingNotification,
+ type_payloads,
+ source);
}
NonBlockingInvalidationNotifier::NonBlockingInvalidationNotifier(
@@ -247,19 +254,25 @@ void NonBlockingInvalidationNotifier::SendNotification(
// need to forward on the call.
}
-void NonBlockingInvalidationNotifier::OnIncomingNotification(
- const syncable::ModelTypePayloadMap& type_payloads,
- IncomingNotificationSource source) {
+void NonBlockingInvalidationNotifier::OnNotificationsEnabled() {
DCHECK(parent_task_runner_->BelongsToCurrentThread());
FOR_EACH_OBSERVER(SyncNotifierObserver, observers_,
- OnIncomingNotification(type_payloads, source));
+ OnNotificationsEnabled());
+}
+
+void NonBlockingInvalidationNotifier::OnNotificationsDisabled(
+ NotificationsDisabledReason reason) {
+ DCHECK(parent_task_runner_->BelongsToCurrentThread());
+ FOR_EACH_OBSERVER(SyncNotifierObserver, observers_,
+ OnNotificationsDisabled(reason));
}
-void NonBlockingInvalidationNotifier::OnNotificationStateChange(
- bool notifications_enabled) {
+void NonBlockingInvalidationNotifier::OnIncomingNotification(
+ const syncable::ModelTypePayloadMap& type_payloads,
+ IncomingNotificationSource source) {
DCHECK(parent_task_runner_->BelongsToCurrentThread());
FOR_EACH_OBSERVER(SyncNotifierObserver, observers_,
- OnNotificationStateChange(notifications_enabled));
+ OnIncomingNotification(type_payloads, source));
}
} // namespace sync_notifier
diff --git a/sync/notifier/non_blocking_invalidation_notifier.h b/sync/notifier/non_blocking_invalidation_notifier.h
index dfcf63f..ff59c43 100644
--- a/sync/notifier/non_blocking_invalidation_notifier.h
+++ b/sync/notifier/non_blocking_invalidation_notifier.h
@@ -57,10 +57,12 @@ class NonBlockingInvalidationNotifier
syncable::ModelTypeSet changed_types) OVERRIDE;
// SyncNotifierObserver implementation.
+ virtual void OnNotificationsEnabled() OVERRIDE;
+ virtual void OnNotificationsDisabled(
+ NotificationsDisabledReason reason) OVERRIDE;
virtual void OnIncomingNotification(
const syncable::ModelTypePayloadMap& type_payloads,
IncomingNotificationSource source) OVERRIDE;
- virtual void OnNotificationStateChange(bool notifications_enabled) OVERRIDE;
private:
class Core;
diff --git a/sync/notifier/non_blocking_invalidation_notifier_unittest.cc b/sync/notifier/non_blocking_invalidation_notifier_unittest.cc
index 42cc5d1..831b443 100644
--- a/sync/notifier/non_blocking_invalidation_notifier_unittest.cc
+++ b/sync/notifier/non_blocking_invalidation_notifier_unittest.cc
@@ -73,20 +73,26 @@ TEST_F(NonBlockingInvalidationNotifierTest, Basic) {
type_payloads[syncable::BOOKMARKS] = "";
type_payloads[syncable::AUTOFILL] = "";
- EXPECT_CALL(mock_observer_, OnNotificationStateChange(true));
+ EXPECT_CALL(mock_observer_, OnNotificationsEnabled());
EXPECT_CALL(mock_observer_,
OnIncomingNotification(type_payloads,
REMOTE_NOTIFICATION));
- EXPECT_CALL(mock_observer_, OnNotificationStateChange(false));
+ EXPECT_CALL(mock_observer_,
+ OnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR));
+ EXPECT_CALL(mock_observer_,
+ OnNotificationsDisabled(NOTIFICATION_CREDENTIALS_REJECTED));
invalidation_notifier_->SetStateDeprecated("fake_state");
invalidation_notifier_->SetUniqueId("fake_id");
invalidation_notifier_->UpdateCredentials("foo@bar.com", "fake_token");
- invalidation_notifier_->OnNotificationStateChange(true);
+ invalidation_notifier_->OnNotificationsEnabled();
invalidation_notifier_->OnIncomingNotification(type_payloads,
REMOTE_NOTIFICATION);
- invalidation_notifier_->OnNotificationStateChange(false);
+ invalidation_notifier_->OnNotificationsDisabled(
+ TRANSIENT_NOTIFICATION_ERROR);
+ invalidation_notifier_->OnNotificationsDisabled(
+ NOTIFICATION_CREDENTIALS_REJECTED);
ui_loop_.RunAllPending();
}
diff --git a/sync/notifier/notifications_disabled_reason.cc b/sync/notifier/notifications_disabled_reason.cc
new file mode 100644
index 0000000..9503140
--- /dev/null
+++ b/sync/notifier/notifications_disabled_reason.cc
@@ -0,0 +1,41 @@
+// Copyright (c) 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 "sync/notifier/notifications_disabled_reason.h"
+
+#include "base/logging.h"
+
+namespace sync_notifier {
+
+const char* NotificationsDisabledReasonToString(
+ NotificationsDisabledReason reason) {
+ switch (reason) {
+ case NO_NOTIFICATION_ERROR:
+ return "NO_NOTIFICATION_ERROR";
+ case TRANSIENT_NOTIFICATION_ERROR:
+ return "TRANSIENT_NOTIFICATION_ERROR";
+ case NOTIFICATION_CREDENTIALS_REJECTED:
+ return "NOTIFICATION_CREDENTIALS_REJECTED";
+ default:
+ NOTREACHED();
+ return "UNKNOWN";
+ }
+}
+
+NotificationsDisabledReason FromNotifierReason(
+ notifier::NotificationsDisabledReason reason) {
+ switch (reason) {
+ case notifier::NO_NOTIFICATION_ERROR:
+ return NO_NOTIFICATION_ERROR;
+ case notifier::TRANSIENT_NOTIFICATION_ERROR:
+ return TRANSIENT_NOTIFICATION_ERROR;
+ case notifier::NOTIFICATION_CREDENTIALS_REJECTED:
+ return NOTIFICATION_CREDENTIALS_REJECTED;
+ default:
+ NOTREACHED();
+ return TRANSIENT_NOTIFICATION_ERROR;
+ }
+}
+
+} // sync_notifier
diff --git a/sync/notifier/notifications_disabled_reason.h b/sync/notifier/notifications_disabled_reason.h
new file mode 100644
index 0000000..75239cd
--- /dev/null
+++ b/sync/notifier/notifications_disabled_reason.h
@@ -0,0 +1,33 @@
+// Copyright (c) 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 SYNC_NOTIFIER_NOTIFICATIONS_DISABLED_REASON_H_
+#define SYNC_NOTIFIER_NOTIFICATIONS_DISABLED_REASON_H_
+#pragma once
+
+#include "jingle/notifier/listener/push_client_observer.h"
+
+namespace sync_notifier {
+
+enum NotificationsDisabledReason {
+ // There is an underlying transient problem (e.g., network- or
+ // XMPP-related).
+ TRANSIENT_NOTIFICATION_ERROR,
+ DEFAULT_NOTIFICATION_ERROR = TRANSIENT_NOTIFICATION_ERROR,
+ // Our credentials have been rejected.
+ NOTIFICATION_CREDENTIALS_REJECTED,
+ // No error (useful as a default value or to avoid keeping a
+ // separate bool for notifications enabled/disabled).
+ NO_NOTIFICATION_ERROR
+};
+
+const char* NotificationsDisabledReasonToString(
+ NotificationsDisabledReason reason);
+
+NotificationsDisabledReason FromNotifierReason(
+ notifier::NotificationsDisabledReason reason);
+
+} // namespace sync_notifier
+
+#endif // SYNC_NOTIFIER_NOTIFICATIONS_DISABLED_REASON_H_
diff --git a/sync/notifier/p2p_notifier.cc b/sync/notifier/p2p_notifier.cc
index 2eae246..211cb2a 100644
--- a/sync/notifier/p2p_notifier.cc
+++ b/sync/notifier/p2p_notifier.cc
@@ -212,19 +212,28 @@ void P2PNotifier::SendNotification(
SendNotificationData(notification_data);
}
-void P2PNotifier::OnNotificationStateChange(bool notifications_enabled) {
+void P2PNotifier::OnNotificationsEnabled() {
DCHECK(non_thread_safe_.CalledOnValidThread());
- bool disabled_to_enabled = notifications_enabled && !notifications_enabled_;
- notifications_enabled_ = notifications_enabled;
- FOR_EACH_OBSERVER(SyncNotifierObserver, observer_list_,
- OnNotificationStateChange(notifications_enabled_));
- if (disabled_to_enabled) {
+ bool just_turned_on = (notifications_enabled_ == false);
+ notifications_enabled_ = true;
+ FOR_EACH_OBSERVER(
+ SyncNotifierObserver, observer_list_,
+ OnNotificationsEnabled());
+ if (just_turned_on) {
const P2PNotificationData notification_data(
unique_id_, NOTIFY_SELF, enabled_types_);
SendNotificationData(notification_data);
}
}
+void P2PNotifier::OnNotificationsDisabled(
+ notifier::NotificationsDisabledReason reason) {
+ DCHECK(non_thread_safe_.CalledOnValidThread());
+ FOR_EACH_OBSERVER(
+ SyncNotifierObserver, observer_list_,
+ OnNotificationsDisabled(FromNotifierReason(reason)));
+}
+
void P2PNotifier::OnIncomingNotification(
const notifier::Notification& notification) {
DCHECK(non_thread_safe_.CalledOnValidThread());
@@ -234,7 +243,7 @@ void P2PNotifier::OnIncomingNotification(
return;
}
if (!notifications_enabled_) {
- DVLOG(1) << "Notifications not enabled -- not emitting notification";
+ DVLOG(1) << "Notifications not on -- not emitting notification";
return;
}
if (notification.channel != kSyncP2PNotificationChannel) {
diff --git a/sync/notifier/p2p_notifier.h b/sync/notifier/p2p_notifier.h
index 341bc8b..2243ff4 100644
--- a/sync/notifier/p2p_notifier.h
+++ b/sync/notifier/p2p_notifier.h
@@ -18,6 +18,7 @@
#include "base/threading/non_thread_safe.h"
#include "jingle/notifier/listener/push_client_observer.h"
#include "sync/internal_api/public/syncable/model_type.h"
+#include "sync/notifier/notifications_disabled_reason.h"
#include "sync/notifier/sync_notifier.h"
namespace notifier {
@@ -107,7 +108,9 @@ class P2PNotifier
syncable::ModelTypeSet changed_types) OVERRIDE;
// PushClientObserver implementation.
- virtual void OnNotificationStateChange(bool notifications_enabled) OVERRIDE;
+ virtual void OnNotificationsEnabled() OVERRIDE;
+ virtual void OnNotificationsDisabled(
+ notifier::NotificationsDisabledReason reason) OVERRIDE;
virtual void OnIncomingNotification(
const notifier::Notification& notification) OVERRIDE;
@@ -127,8 +130,6 @@ class P2PNotifier
std::string unique_id_;
// Whether we have called UpdateCredentials() yet.
bool logged_in_;
- // Whether |push_client_| has notified us that notifications are
- // enabled.
bool notifications_enabled_;
// Which set of clients should be sent notifications.
P2PNotificationTarget send_notification_target_;
diff --git a/sync/notifier/p2p_notifier_unittest.cc b/sync/notifier/p2p_notifier_unittest.cc
index 28ec600..d1ed20d 100644
--- a/sync/notifier/p2p_notifier_unittest.cc
+++ b/sync/notifier/p2p_notifier_unittest.cc
@@ -145,7 +145,7 @@ TEST_F(P2PNotifierTest, NotificationsBasic) {
syncable::ModelTypeSet enabled_types(
syncable::BOOKMARKS, syncable::PREFERENCES);
- EXPECT_CALL(mock_observer_, OnNotificationStateChange(true));
+ EXPECT_CALL(mock_observer_, OnNotificationsEnabled());
EXPECT_CALL(mock_observer_,
OnIncomingNotification(MakePayloadMap(enabled_types),
REMOTE_NOTIFICATION));
@@ -169,7 +169,7 @@ TEST_F(P2PNotifierTest, NotificationsBasic) {
p2p_notifier_.UpdateEnabledTypes(enabled_types);
ReflectSentNotifications();
- fake_push_client_->SimulateNotificationStateChange(true);
+ fake_push_client_->EnableNotifications();
// Sent with target NOTIFY_OTHERS so should not be propagated to
// |mock_observer_|.
@@ -195,7 +195,7 @@ TEST_F(P2PNotifierTest, SendNotificationData) {
const syncable::ModelTypePayloadMap& changed_payload_map =
MakePayloadMap(changed_types);
- EXPECT_CALL(mock_observer_, OnNotificationStateChange(true));
+ EXPECT_CALL(mock_observer_, OnNotificationsEnabled());
EXPECT_CALL(mock_observer_,
OnIncomingNotification(MakePayloadMap(enabled_types),
REMOTE_NOTIFICATION));
@@ -205,7 +205,7 @@ TEST_F(P2PNotifierTest, SendNotificationData) {
p2p_notifier_.UpdateEnabledTypes(enabled_types);
ReflectSentNotifications();
- fake_push_client_->SimulateNotificationStateChange(true);
+ fake_push_client_->EnableNotifications();
ReflectSentNotifications();
diff --git a/sync/notifier/push_client_channel.cc b/sync/notifier/push_client_channel.cc
index cfd3129..4ef60bc 100644
--- a/sync/notifier/push_client_channel.cc
+++ b/sync/notifier/push_client_channel.cc
@@ -62,12 +62,20 @@ void PushClientChannel::SetSystemResources(
// Do nothing.
}
-void PushClientChannel::OnNotificationStateChange(
- bool notifications_enabled) {
+void PushClientChannel::OnNotificationsEnabled() {
for (NetworkStatusReceiverList::const_iterator it =
network_status_receivers_.begin();
it != network_status_receivers_.end(); ++it) {
- (*it)->Run(notifications_enabled);
+ (*it)->Run(true);
+ }
+}
+
+void PushClientChannel::OnNotificationsDisabled(
+ notifier::NotificationsDisabledReason reason) {
+ for (NetworkStatusReceiverList::const_iterator it =
+ network_status_receivers_.begin();
+ it != network_status_receivers_.end(); ++it) {
+ (*it)->Run(false);
}
}
diff --git a/sync/notifier/push_client_channel.h b/sync/notifier/push_client_channel.h
index 1721def..8ad1853 100644
--- a/sync/notifier/push_client_channel.h
+++ b/sync/notifier/push_client_channel.h
@@ -27,6 +27,8 @@ class PushClientChannel
: public invalidation::NetworkChannel,
public notifier::PushClientObserver {
public:
+ // |push_client| is guaranteed to be destroyed only when this object
+ // is destroyed.
explicit PushClientChannel(scoped_ptr<notifier::PushClient> push_client);
virtual ~PushClientChannel();
@@ -46,7 +48,9 @@ class PushClientChannel
invalidation::SystemResources* resources) OVERRIDE;
// notifier::PushClient::Observer implementation.
- virtual void OnNotificationStateChange(bool notifications_enabled) OVERRIDE;
+ virtual void OnNotificationsEnabled() OVERRIDE;
+ virtual void OnNotificationsDisabled(
+ notifier::NotificationsDisabledReason reason) OVERRIDE;
virtual void OnIncomingNotification(
const notifier::Notification& notification) OVERRIDE;
diff --git a/sync/notifier/push_client_channel_unittest.cc b/sync/notifier/push_client_channel_unittest.cc
index e179109..f63cb86 100644
--- a/sync/notifier/push_client_channel_unittest.cc
+++ b/sync/notifier/push_client_channel_unittest.cc
@@ -151,13 +151,19 @@ TEST_F(PushClientChannelTest, SendMessage) {
expected_notification));
}
-// Simulate notification state changes on the push client. It should
+// Simulate push client state changes on the push client. It should
// propagate to the channel.
-TEST_F(PushClientChannelTest, OnNotificationStateChange) {
+TEST_F(PushClientChannelTest, OnPushClientStateChange) {
EXPECT_FALSE(connected_);
- fake_push_client_->SimulateNotificationStateChange(true);
+ fake_push_client_->EnableNotifications();
EXPECT_TRUE(connected_);
- fake_push_client_->SimulateNotificationStateChange(false);
+ fake_push_client_->DisableNotifications(
+ notifier::TRANSIENT_NOTIFICATION_ERROR);
+ EXPECT_FALSE(connected_);
+ fake_push_client_->EnableNotifications();
+ EXPECT_TRUE(connected_);
+ fake_push_client_->DisableNotifications(
+ notifier::NOTIFICATION_CREDENTIALS_REJECTED);
EXPECT_FALSE(connected_);
}
diff --git a/sync/notifier/sync_notifier_observer.h b/sync/notifier/sync_notifier_observer.h
index 0685528..4ca43dc 100644
--- a/sync/notifier/sync_notifier_observer.h
+++ b/sync/notifier/sync_notifier_observer.h
@@ -6,9 +6,8 @@
#define SYNC_NOTIFIER_SYNC_NOTIFIER_OBSERVER_H_
#pragma once
-#include <string>
-
#include "sync/internal_api/public/syncable/model_type_payload_map.h"
+#include "sync/notifier/notifications_disabled_reason.h"
namespace sync_notifier {
@@ -21,10 +20,19 @@ enum IncomingNotificationSource {
class SyncNotifierObserver {
public:
+ // Called when notifications are enabled.
+ virtual void OnNotificationsEnabled() = 0;
+
+ // Called when notifications are disabled, with the reason in
+ // |reason|.
+ virtual void OnNotificationsDisabled(
+ NotificationsDisabledReason reason) = 0;
+
+ // Called when a notification is received. The per-type payloads
+ // are in |type_payloads| and the source is in |source|.
virtual void OnIncomingNotification(
const syncable::ModelTypePayloadMap& type_payloads,
IncomingNotificationSource source) = 0;
- virtual void OnNotificationStateChange(bool notifications_enabled) = 0;
protected:
virtual ~SyncNotifierObserver() {}
diff --git a/sync/sync.gyp b/sync/sync.gyp
index 934d318..5413055 100644
--- a/sync/sync.gyp
+++ b/sync/sync.gyp
@@ -219,6 +219,8 @@
'../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation',
],
'sources': [
+ 'notifier/notifications_disabled_reason.h',
+ 'notifier/notifications_disabled_reason.cc',
'notifier/sync_notifier.h',
'notifier/sync_notifier_factory.h',
'notifier/sync_notifier_factory.cc',
diff --git a/sync/tools/sync_listen_notifications.cc b/sync/tools/sync_listen_notifications.cc
index 52e2efa..d160285 100644
--- a/sync/tools/sync_listen_notifications.cc
+++ b/sync/tools/sync_listen_notifications.cc
@@ -38,6 +38,16 @@ class NotificationPrinter : public sync_notifier::SyncNotifierObserver {
NotificationPrinter() {}
virtual ~NotificationPrinter() {}
+ virtual void OnNotificationsEnabled() OVERRIDE {
+ LOG(INFO) << "Notifications enabled";
+ }
+
+ virtual void OnNotificationsDisabled(
+ sync_notifier::NotificationsDisabledReason reason) OVERRIDE {
+ LOG(INFO) << "Notifications disabled with reason "
+ << sync_notifier::NotificationsDisabledReasonToString(reason);
+ }
+
virtual void OnIncomingNotification(
const syncable::ModelTypePayloadMap& type_payloads,
sync_notifier::IncomingNotificationSource source) OVERRIDE {
@@ -51,11 +61,6 @@ class NotificationPrinter : public sync_notifier::SyncNotifierObserver {
}
}
- virtual void OnNotificationStateChange(
- bool notifications_enabled) OVERRIDE {
- LOG(INFO) << "Notifications enabled: " << notifications_enabled;
- }
-
private:
DISALLOW_COPY_AND_ASSIGN(NotificationPrinter);
};