| 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 56497a741f085725b8ad2b232d2c69e70fdf0cdf..58dd4333c6ad17dad2244882a60ef242d8394295 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,9 @@ 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);
|
| + RestoreDismissedCategory(category_provider_pair.first);
|
| }
|
| + StoreDismissedCategoriesToPrefs();
|
| DCHECK(dismissed_providers_by_category_.empty());
|
| }
|
|
|
| @@ -189,8 +202,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))) {
|
| // A provider shouldn't send us suggestions while it's not available.
|
| @@ -212,19 +236,17 @@ void ContentSuggestionsService::OnCategoryStatusChanged(
|
| ContentSuggestionsProvider* provider,
|
| Category category,
|
| CategoryStatus new_status) {
|
| - if (!IsCategoryStatusAvailable(new_status)) {
|
| - suggestions_by_category_.erase(category);
|
| - }
|
| 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(
|
| @@ -281,7 +303,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);
|
| @@ -292,10 +314,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();
|
| @@ -303,7 +342,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(
|
| @@ -353,4 +407,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(base::ContainsKey(dismissed_providers_by_category_, category));
|
| +
|
| + // 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
|
|
|