Chromium Code Reviews| Index: components/ntp_snippets/content_suggestions_service.cc |
| diff --git a/components/ntp_snippets/content_suggestions_service.cc b/components/ntp_snippets/content_suggestions_service.cc |
| index 8b1bdc15eae83a3180fece814448f8805d01484f..6c539df1275d7eafd154edad8c94494e88893214 100644 |
| --- a/components/ntp_snippets/content_suggestions_service.cc |
| +++ b/components/ntp_snippets/content_suggestions_service.cc |
| @@ -13,6 +13,10 @@ |
| #include "base/location.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| +#include "base/values.h" |
| +#include "components/ntp_snippets/pref_names.h" |
| +#include "components/prefs/pref_registry_simple.h" |
| +#include "components/prefs/pref_service.h" |
| #include "ui/gfx/image/image.h" |
| namespace ntp_snippets { |
| @@ -24,10 +28,13 @@ ContentSuggestionsService::ContentSuggestionsService( |
| : state_(state), |
| history_service_observer_(this), |
| ntp_snippets_service_(nullptr), |
| + pref_service_(pref_service), |
| user_classifier_(pref_service) { |
| // Can be null in tests. |
| if (history_service) |
| history_service_observer_.Add(history_service); |
| + |
| + RestoreDismissedCategoriesFromPrefs(); |
| } |
| ContentSuggestionsService::~ContentSuggestionsService() = default; |
| @@ -42,6 +49,12 @@ void ContentSuggestionsService::Shutdown() { |
| FOR_EACH_OBSERVER(Observer, observers_, ContentSuggestionsServiceShutdown()); |
| } |
| +// static |
| +void ContentSuggestionsService::RegisterProfilePrefs( |
| + PrefRegistrySimple* registry) { |
| + registry->RegisterListPref(prefs::kDismissedCategories); |
| +} |
| + |
| CategoryStatus ContentSuggestionsService::GetCategoryStatus( |
| Category category) const { |
| if (state_ == State::DISABLED) { |
| @@ -150,11 +163,11 @@ void ContentSuggestionsService::DismissCategory(Category category) { |
| if (providers_it == providers_by_category_.end()) |
| return; |
| - suggestions_by_category_[category].clear(); |
| - dismissed_providers_by_category_[providers_it->first] = providers_it->second; |
| - providers_by_category_.erase(providers_it); |
| - categories_.erase( |
| - std::find(categories_.begin(), categories_.end(), category)); |
| + ContentSuggestionsProvider* provider = providers_it->second; |
| + UnregisterCategory(category, provider); |
| + |
| + dismissed_providers_by_category_[category] = provider; |
| + StoreDismissedCategoriesToPrefs(); |
| } |
| void ContentSuggestionsService::RestoreDismissedCategories() { |
| @@ -162,9 +175,14 @@ void ContentSuggestionsService::RestoreDismissedCategories() { |
| auto dismissed_providers_by_category_copy = dismissed_providers_by_category_; |
| for (const auto& category_provider_pair : |
| dismissed_providers_by_category_copy) { |
| - RegisterCategoryIfRequired(category_provider_pair.second, |
| - category_provider_pair.first); |
| + if (category_provider_pair.second) { |
| + RestoreDismissedCategory(category_provider_pair.first); |
| + } else { |
| + // There is no provider for this category, we just remove the entry. |
| + dismissed_providers_by_category_.erase(category_provider_pair.first); |
|
Marc Treib
2016/10/17 08:44:46
I think RestoreDismissedCategory now handles a nul
dgn
2016/10/17 16:41:50
Done.
|
| + } |
| } |
| + StoreDismissedCategoriesToPrefs(); |
| DCHECK(dismissed_providers_by_category_.empty()); |
| } |
| @@ -189,8 +207,19 @@ void ContentSuggestionsService::OnNewSuggestions( |
| ContentSuggestionsProvider* provider, |
| Category category, |
| std::vector<ContentSuggestion> suggestions) { |
| - if (RegisterCategoryIfRequired(provider, category)) |
| + if (TryRegisterProviderForCategory(provider, category)) { |
| + NotifyCategoryStatusChanged(category); |
| + } else if (IsCategoryDismissed(category)) { |
| + // The category has been registered as a dismissed one. We need to |
| + // check if the dismissal can be cleared now that we received new data. |
| + if (suggestions.empty()) |
| + return; |
| + |
| + RestoreDismissedCategory(category); |
| + StoreDismissedCategoriesToPrefs(); |
| + |
| NotifyCategoryStatusChanged(category); |
| + } |
| if (!IsCategoryStatusAvailable(provider->GetCategoryStatus(category))) |
| return; |
| @@ -213,15 +242,16 @@ void ContentSuggestionsService::OnCategoryStatusChanged( |
| suggestions_by_category_.erase(category); |
|
Marc Treib
2016/10/17 08:44:46
I think this can be removed, since there's now ano
dgn
2016/10/17 16:41:50
Done.
|
| } |
| if (new_status == CategoryStatus::NOT_PROVIDED) { |
| - DCHECK(providers_by_category_.find(category) != |
| - providers_by_category_.end()); |
| - DCHECK_EQ(provider, providers_by_category_.find(category)->second); |
| - DismissCategory(category); |
| + UnregisterCategory(category, provider); |
| } else { |
| - RegisterCategoryIfRequired(provider, category); |
| + if (!IsCategoryStatusAvailable(new_status)) |
| + suggestions_by_category_.erase(category); |
| + TryRegisterProviderForCategory(provider, category); |
| DCHECK_EQ(new_status, provider->GetCategoryStatus(category)); |
| } |
| - NotifyCategoryStatusChanged(category); |
| + |
| + if (!IsCategoryDismissed(category)) |
| + NotifyCategoryStatusChanged(category); |
| } |
| void ContentSuggestionsService::OnSuggestionInvalidated( |
| @@ -278,7 +308,7 @@ void ContentSuggestionsService::HistoryServiceBeingDeleted( |
| history_service_observer_.RemoveAll(); |
| } |
| -bool ContentSuggestionsService::RegisterCategoryIfRequired( |
| +bool ContentSuggestionsService::TryRegisterProviderForCategory( |
| ContentSuggestionsProvider* provider, |
| Category category) { |
| auto it = providers_by_category_.find(category); |
| @@ -289,10 +319,27 @@ bool ContentSuggestionsService::RegisterCategoryIfRequired( |
| auto dismissed_it = dismissed_providers_by_category_.find(category); |
| if (dismissed_it != dismissed_providers_by_category_.end()) { |
| - DCHECK_EQ(dismissed_it->second, provider); |
| - dismissed_providers_by_category_.erase(dismissed_it); |
| + // The initialisation of dismissed categories registers them with |nullptr| |
| + // for providers, we need to check for that to see if the provider is |
| + // already registered or not. |
| + if (!dismissed_it->second) { |
| + dismissed_it->second = provider; |
| + } else { |
| + DCHECK_EQ(dismissed_it->second, provider); |
| + } |
| + return false; |
| } |
| + RegisterCategory(category, provider); |
| + return true; |
| +} |
| + |
| +void ContentSuggestionsService::RegisterCategory( |
| + Category category, |
| + ContentSuggestionsProvider* provider) { |
| + DCHECK(!base::ContainsKey(providers_by_category_, category)); |
| + DCHECK(!IsCategoryDismissed(category)); |
| + |
| providers_by_category_[category] = provider; |
| categories_.push_back(category); |
| SortCategories(); |
| @@ -300,7 +347,22 @@ bool ContentSuggestionsService::RegisterCategoryIfRequired( |
| suggestions_by_category_.insert( |
| std::make_pair(category, std::vector<ContentSuggestion>())); |
| } |
| - return true; |
| +} |
| + |
| +void ContentSuggestionsService::UnregisterCategory( |
| + Category category, |
| + ContentSuggestionsProvider* provider) { |
| + auto providers_it = providers_by_category_.find(category); |
| + if (providers_it == providers_by_category_.end()) { |
| + DCHECK(IsCategoryDismissed(category)); |
| + return; |
| + } |
| + |
| + DCHECK_EQ(provider, providers_it->second); |
| + providers_by_category_.erase(providers_it); |
| + categories_.erase( |
| + std::find(categories_.begin(), categories_.end(), category)); |
| + suggestions_by_category_.erase(category); |
| } |
| bool ContentSuggestionsService::RemoveSuggestionByID( |
| @@ -350,4 +412,50 @@ void ContentSuggestionsService::SortCategories() { |
| }); |
| } |
| +bool ContentSuggestionsService::IsCategoryDismissed(Category category) const { |
| + return base::ContainsKey(dismissed_providers_by_category_, category); |
| +} |
| + |
| +void ContentSuggestionsService::RestoreDismissedCategory(Category category) { |
| + auto dismissed_it = dismissed_providers_by_category_.find(category); |
| + DCHECK(dismissed_it != dismissed_providers_by_category_.end()); |
|
Marc Treib
2016/10/17 08:44:46
DCHECK_NE? Or alternatively, DCHECK(base::Contains
dgn
2016/10/17 16:41:50
Done.
|
| + |
| + // Keep the reference to the provider and remove it from the dismissed ones, |
| + // because the category registration enforces that it's not dismissed. |
| + ContentSuggestionsProvider* provider = dismissed_it->second; |
| + dismissed_providers_by_category_.erase(dismissed_it); |
| + |
| + if (provider) |
| + RegisterCategory(category, provider); |
| +} |
| + |
| +void ContentSuggestionsService::RestoreDismissedCategoriesFromPrefs() { |
| + // This must only be called at startup. |
| + DCHECK(dismissed_providers_by_category_.empty()); |
| + DCHECK(providers_by_category_.empty()); |
| + |
| + const base::ListValue* list = |
| + pref_service_->GetList(prefs::kDismissedCategories); |
| + for (const std::unique_ptr<base::Value>& entry : *list) { |
| + int id = 0; |
| + if (!entry->GetAsInteger(&id)) { |
| + DLOG(WARNING) << "Invalid category pref value: " << *entry; |
| + continue; |
| + } |
| + |
| + // When the provider is registered, it will be stored in this map. |
| + dismissed_providers_by_category_[category_factory()->FromIDValue(id)] = |
| + nullptr; |
| + } |
| +} |
| + |
| +void ContentSuggestionsService::StoreDismissedCategoriesToPrefs() { |
| + base::ListValue list; |
| + for (const auto& category_provider_pair : dismissed_providers_by_category_) { |
| + list.AppendInteger(category_provider_pair.first.id()); |
| + } |
| + |
| + pref_service_->Set(prefs::kDismissedCategories, list); |
| +} |
| + |
| } // namespace ntp_snippets |