Chromium Code Reviews| Index: components/ntp_snippets/ntp_snippets_service.cc |
| diff --git a/components/ntp_snippets/ntp_snippets_service.cc b/components/ntp_snippets/ntp_snippets_service.cc |
| index 60a87b6895d1e8f6ef773ca95d6fe22c8ad1912c..d15de22dde8a56f9ffcbcc8144de374089ff0105 100644 |
| --- a/components/ntp_snippets/ntp_snippets_service.cc |
| +++ b/components/ntp_snippets/ntp_snippets_service.cc |
| @@ -187,8 +187,8 @@ NTPSnippetsService::NTPSnippetsService( |
| std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher, |
| std::unique_ptr<ImageFetcher> image_fetcher, |
| std::unique_ptr<NTPSnippetsDatabase> database) |
| - : state_(State::INITED), |
| - enabled_(enabled), |
| + : state_(State::NOT_INITED), |
| + explicitly_disabled_(!enabled), |
| pref_service_(pref_service), |
| sync_service_(sync_service), |
| sync_service_observer_(this), |
| @@ -199,21 +199,27 @@ NTPSnippetsService::NTPSnippetsService( |
| image_fetcher_(std::move(image_fetcher)), |
| database_(std::move(database)), |
| fetch_after_load_(false) { |
| + // TODO(dgn) should be removed after branch point (https:://crbug.com/617585). |
| + ClearDeprecatedPrefs(); |
| + |
| + if (explicitly_disabled_) { |
| + EnterState(State::DISABLED); |
| + return; |
| + } |
| + |
| snippets_fetcher_->SetCallback(base::Bind( |
| &NTPSnippetsService::OnFetchFinished, base::Unretained(this))); |
| // |sync_service_| can be null in tests or if sync is disabled. |
| + // This is a service we want to keep listening to all the time, independently |
| + // from the state, since it will allow us to enable or disabled the snippets |
|
Marc Treib
2016/06/07 08:55:39
nit: disable, no "d"
dgn
2016/06/07 11:22:46
Done.
|
| + // service. |
| if (sync_service_) |
| sync_service_observer_.Add(sync_service_); |
| - if (enabled_) { |
| - database_->Load(base::Bind(&NTPSnippetsService::OnDatabaseLoaded, |
| - base::Unretained(this))); |
| - } |
| - |
| - RescheduleFetching(); |
| - |
| - ClearDeprecatedPrefs(); |
| + // Will trigger the transition to the READY state. |
| + database_->Load(base::Bind(&NTPSnippetsService::OnDatabaseLoaded, |
| + base::Unretained(this))); |
| } |
| NTPSnippetsService::~NTPSnippetsService() { |
| @@ -227,19 +233,13 @@ void NTPSnippetsService::RegisterProfilePrefs(PrefRegistrySimple* registry) { |
| registry->RegisterListPref(prefs::kSnippetHosts); |
| } |
| +// Inherited from KeyedService. |
| void NTPSnippetsService::Shutdown() { |
| - DCHECK(state_ == State::INITED || state_ == State::LOADED); |
| - state_ = State::SHUT_DOWN; |
| - |
| - FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, |
| - NTPSnippetsServiceShutdown()); |
| - expiry_timer_.Stop(); |
| - suggestions_service_subscription_.reset(); |
| - enabled_ = false; |
| + EnterState(State::SHUT_DOWN); |
| } |
| void NTPSnippetsService::FetchSnippets() { |
| - if (loaded()) |
| + if (ready()) |
| FetchSnippetsFromHosts(GetSuggestionsHosts()); |
| else |
| fetch_after_load_ = true; |
| @@ -247,7 +247,7 @@ void NTPSnippetsService::FetchSnippets() { |
| void NTPSnippetsService::FetchSnippetsFromHosts( |
| const std::set<std::string>& hosts) { |
| - if (!loaded()) |
| + if (!ready()) |
| return; |
| snippets_fetcher_->FetchSnippetsFromHosts(hosts, application_language_code_, |
| kMaxSnippetCount); |
| @@ -258,7 +258,7 @@ void NTPSnippetsService::RescheduleFetching() { |
| if (!scheduler_) |
| return; |
| - if (enabled_) { |
| + if (ready()) { |
| base::Time now = base::Time::Now(); |
| scheduler_->Schedule( |
| GetFetchingIntervalWifiCharging(), GetFetchingIntervalWifi(now), |
| @@ -289,7 +289,10 @@ void NTPSnippetsService::FetchSnippetImage( |
| } |
| void NTPSnippetsService::ClearSnippets() { |
| - if (!loaded()) |
| + if (!initialized()) |
| + return; |
| + |
| + if (snippets_.empty()) |
| return; |
| database_->Delete(snippets_); |
| @@ -310,7 +313,7 @@ std::set<std::string> NTPSnippetsService::GetSuggestionsHosts() const { |
| } |
| bool NTPSnippetsService::DiscardSnippet(const std::string& snippet_id) { |
| - if (!loaded()) |
| + if (!ready()) |
| return false; |
| auto it = |
| @@ -334,13 +337,11 @@ bool NTPSnippetsService::DiscardSnippet(const std::string& snippet_id) { |
| } |
| void NTPSnippetsService::ClearDiscardedSnippets() { |
| - if (!loaded()) |
| + if (!initialized()) |
| return; |
| database_->Delete(discarded_snippets_); |
| discarded_snippets_.clear(); |
| - |
| - FetchSnippets(); |
| } |
| void NTPSnippetsService::AddObserver(NTPSnippetsServiceObserver* observer) { |
| @@ -351,6 +352,34 @@ void NTPSnippetsService::RemoveObserver(NTPSnippetsServiceObserver* observer) { |
| observers_.RemoveObserver(observer); |
| } |
| +DisabledReason NTPSnippetsService::GetDisabledReason() const { |
| + if (explicitly_disabled_) |
| + return DisabledReason::EXPLICITLY_DISABLED; |
| + |
| + if (!sync_service_ || !sync_service_->CanSyncStart()) { |
| + DVLOG(1) << "[GetDisabledReason] Sync disabled"; |
| + return DisabledReason::HISTORY_SYNC_DISABLED; |
| + } |
| + |
| + // !IsSyncActive in cases where CanSyncStart is true hints at the backend not |
| + // being initialized. |
| + // ConfigurationDone() verifies that the sync service has properly loaded its |
| + // configuration and is aware of the different data types to sync. |
| + if (!sync_service_->IsSyncActive() || !sync_service_->ConfigurationDone()) { |
| + DVLOG(1) << "[GetDisabledReason] Sync initialization is not complete."; |
| + return DisabledReason::HISTORY_SYNC_STATE_UNKNOWN; |
| + } |
| + |
| + if (!sync_service_->GetActiveDataTypes().Has( |
| + syncer::HISTORY_DELETE_DIRECTIVES)) { |
| + DVLOG(1) << "[GetDisabledReason] History sync disabled"; |
| + return DisabledReason::HISTORY_SYNC_DISABLED; |
| + } |
| + |
| + DVLOG(1) << "[GetDisabledReason] Enabled"; |
| + return DisabledReason::NONE; |
| +} |
| + |
| // static |
| int NTPSnippetsService::GetMaxSnippetCountForTesting() { |
| return kMaxSnippetCount; |
| @@ -359,26 +388,18 @@ int NTPSnippetsService::GetMaxSnippetCountForTesting() { |
| //////////////////////////////////////////////////////////////////////////////// |
| // Private methods |
| -// sync_driver::SyncServiceObserver implementation. |
| void NTPSnippetsService::OnStateChanged() { |
| - if (IsSyncStateIncompatible()) { |
| - ClearSnippets(); |
| - FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, |
| - NTPSnippetsServiceDisabled()); |
| + if (!initialized()) |
| return; |
| - } |
| - // TODO(dgn): When the data sources change, we may want to not fetch here, |
| - // as we will get notified of changes from the snippet sources as well, and |
| - // start multiple fetches. |
| - FetchSnippets(); |
| + DVLOG(1) << "[OnStateChanged]"; |
| + EnterState(GetStateForDependenciesStatus()); |
| } |
| void NTPSnippetsService::OnDatabaseLoaded(NTPSnippet::PtrVector snippets) { |
| - DCHECK(state_ == State::INITED || state_ == State::SHUT_DOWN); |
| + DCHECK(state_ == State::NOT_INITED || state_ == State::SHUT_DOWN); |
| if (state_ == State::SHUT_DOWN) |
| return; |
| - state_ = State::LOADED; |
| DCHECK(snippets_.empty()); |
| DCHECK(discarded_snippets_.empty()); |
| @@ -393,15 +414,14 @@ void NTPSnippetsService::OnDatabaseLoaded(NTPSnippet::PtrVector snippets) { |
| const std::unique_ptr<NTPSnippet>& rhs) { |
| return lhs->score() > rhs->score(); |
| }); |
| - LoadingSnippetsFinished(); |
| - // If host restrictions are enabled, register for host list updates. |
| - // |suggestions_service_| can be null in tests. |
| - if (snippets_fetcher_->UsesHostRestrictions() && suggestions_service_) { |
| - suggestions_service_subscription_ = |
| - suggestions_service_->AddCallback(base::Bind( |
| - &NTPSnippetsService::OnSuggestionsChanged, base::Unretained(this))); |
| - } |
| + // Change state after we started loading the snippets. During startup, the |
| + // Sync service might not be completely loaded when we initialize this |
| + // service. Whether we had snippets in the last season is used to guess if |
| + // we should enable the service or not. See |GetStateForDependenciesStatus|. |
| + EnterState(GetStateForDependenciesStatus()); |
| + |
| + LoadingSnippetsFinished(); |
| // Start a fetch if we don't have any snippets yet, or a fetch was requested |
| // earlier. |
| @@ -413,7 +433,7 @@ void NTPSnippetsService::OnDatabaseLoaded(NTPSnippet::PtrVector snippets) { |
| void NTPSnippetsService::OnSuggestionsChanged( |
| const SuggestionsProfile& suggestions) { |
| - DCHECK(loaded()); |
| + DCHECK(initialized()); |
| std::set<std::string> hosts = GetSuggestionsHostsImpl(suggestions); |
| if (hosts == GetSnippetHostsFromPrefs()) |
| @@ -442,7 +462,7 @@ void NTPSnippetsService::OnSuggestionsChanged( |
| void NTPSnippetsService::OnFetchFinished( |
| NTPSnippetsFetcher::OptionalSnippets snippets) { |
| - if (!loaded()) |
| + if (!ready()) |
| return; |
| if (snippets) { |
| @@ -457,7 +477,7 @@ void NTPSnippetsService::OnFetchFinished( |
| } |
| void NTPSnippetsService::MergeSnippets(NTPSnippet::PtrVector new_snippets) { |
| - DCHECK(loaded()); |
| + DCHECK(ready()); |
| // Remove new snippets that we already have, or that have been discarded. |
| std::set<std::string> old_snippet_ids; |
| @@ -540,7 +560,7 @@ void NTPSnippetsService::StoreSnippetHostsToPrefs( |
| } |
| void NTPSnippetsService::LoadingSnippetsFinished() { |
| - DCHECK(loaded()); |
| + DCHECK(ready()); |
| // Remove expired snippets. |
| base::Time expiry = base::Time::Now(); |
| @@ -602,13 +622,105 @@ void NTPSnippetsService::LoadingSnippetsFinished() { |
| base::Unretained(this))); |
| } |
| -bool NTPSnippetsService::IsSyncStateIncompatible() { |
| - if (!sync_service_ || !sync_service_->CanSyncStart()) |
| - return true; |
| - if (!sync_service_->IsSyncActive() || !sync_service_->ConfigurationDone()) |
| - return false; // Sync service is not initialized, yet not disabled. |
| - return !sync_service_->GetActiveDataTypes().Has( |
| - syncer::HISTORY_DELETE_DIRECTIVES); |
| +void NTPSnippetsService::EnterStateEnabled(bool fetch_snippets) { |
| + if (fetch_snippets) |
| + FetchSnippets(); |
| + |
| + // If host restrictions are enabled, register for host list updates. |
| + // |suggestions_service_| can be null in tests. |
| + if (snippets_fetcher_->UsesHostRestrictions() && suggestions_service_) { |
| + suggestions_service_subscription_ = |
| + suggestions_service_->AddCallback(base::Bind( |
| + &NTPSnippetsService::OnSuggestionsChanged, base::Unretained(this))); |
| + } |
| + |
| + RescheduleFetching(); |
| +} |
| + |
| +void NTPSnippetsService::EnterStateDisabled() { |
| + ClearSnippets(); |
| + ClearDiscardedSnippets(); |
| + |
| + suggestions_service_subscription_.reset(); |
| + expiry_timer_.Stop(); |
| + |
| + RescheduleFetching(); |
| + FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, |
| + NTPSnippetsServiceDisabled()); |
| +} |
| + |
| +void NTPSnippetsService::EnterStateShutdown() { |
| + FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, |
| + NTPSnippetsServiceShutdown()); |
| + |
| + expiry_timer_.Stop(); |
| + suggestions_service_subscription_.reset(); |
| + |
| + if (sync_service_) |
| + sync_service_observer_.Remove(sync_service_); |
| +} |
| + |
| +NTPSnippetsService::State NTPSnippetsService::GetStateForDependenciesStatus() { |
| + switch (GetDisabledReason()) { |
| + case DisabledReason::NONE: |
| + return State::READY; |
| + |
| + case DisabledReason::HISTORY_SYNC_STATE_UNKNOWN: |
| + // HistorySync is not initialized yet, so we don't know what the actual |
| + // state is. However, because we retreived the previous snippets from the |
| + // database, if we got something, we know that the service was previously |
| + // enabled, so we just restore that state. If things changed, |
| + // |OnStateChanged| will call this function again to fix the state. |
| + DVLOG(1) << "Sync configuration incomplete, continuing based on the " |
| + "current state."; |
| + return snippets_.empty() ? State::DISABLED : State::READY; |
| + |
| + default: |
|
Marc Treib
2016/06/07 08:55:39
Can we list the remaining cases explicitly here? T
dgn
2016/06/07 11:22:46
Done.
Marc Treib
2016/06/07 11:50:37
You'll have to add a "dummy return" after the swit
dgn
2016/06/07 13:15:00
Doh. And I thought using clang locally would help
|
| + return State::DISABLED; |
| + } |
| +} |
| + |
| +void NTPSnippetsService::EnterState(State state) { |
| + switch (state) { |
| + case State::NOT_INITED: |
| + // Initial state, it should not be possible to get back there. |
| + NOTREACHED(); |
| + return; |
| + |
| + case State::READY: { |
| + DCHECK(state_ == State::NOT_INITED || state_ == State::READY || |
| + state_ == State::DISABLED); |
| + if (state_ == State::READY) |
| + return; |
| + |
| + // During the initialization sequence we will fetch snippets when |
| + // necessary. So we skip it during the state transition. |
| + bool fetch_snippets = state_ != State::NOT_INITED; |
|
Marc Treib
2016/06/07 08:55:39
...so this will only be true when we're going from
dgn
2016/06/07 11:22:46
The snippet DB would be cleared in that case (we d
Marc Treib
2016/06/07 11:50:37
Ah, right - I missed that we're clearing the DB in
dgn
2016/06/07 13:15:00
Done.
|
| + DVLOG(1) << "Entering state: READY"; |
| + state_ = State::READY; |
| + EnterStateEnabled(fetch_snippets); |
| + return; |
| + } |
| + |
| + case State::DISABLED: |
| + DCHECK(state_ == State::NOT_INITED || state_ == State::READY || |
| + state_ == State::DISABLED); |
| + if (state_ == State::DISABLED) |
| + return; |
| + |
| + DVLOG(1) << "Entering state: DISABLED"; |
| + state_ = State::DISABLED; |
| + EnterStateDisabled(); |
| + return; |
| + |
| + case State::SHUT_DOWN: |
| + DCHECK(state_ == State::NOT_INITED || state_ == State::DISABLED || |
| + state_ == State::READY); |
| + DVLOG(1) << "Entering state: SHUT_DOWN"; |
| + state_ = State::SHUT_DOWN; |
| + EnterStateShutdown(); |
| + return; |
| + } |
| } |
| void NTPSnippetsService::ClearDeprecatedPrefs() { |