Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1542)

Unified Diff: components/ntp_snippets/content_suggestions_service.cc

Issue 2406573002: 📰 Persist category dismissals (Closed)
Patch Set: rebase and rewrite Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..61c9368f8eca66b3d469b2c22339e255e14620cb 100644
--- a/components/ntp_snippets/content_suggestions_service.cc
+++ b/components/ntp_snippets/content_suggestions_service.cc
@@ -13,6 +13,9 @@
#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 "ui/gfx/image/image.h"
namespace ntp_snippets {
@@ -24,10 +27,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 +48,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 +162,13 @@ 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));
+ suggestions_by_category_.erase(category);
dgn 2016/10/13 14:46:51 I'm not sure why we just cleared the entry before,
Marc Treib 2016/10/13 15:59:00 No, I think I missed this in a previous CL - erase
dgn 2016/10/14 21:20:28 It's not done currently, but it would make sense t
+ ContentSuggestionsProvider* provider = providers_it->second;
+
+ UnregisterCategory(category, provider);
+
+ dismissed_providers_by_category_[category] = provider;
+ StoreDismissedCategoriesToPrefs();
}
void ContentSuggestionsService::RestoreDismissedCategories() {
@@ -162,9 +176,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);
+ }
}
+ StoreDismissedCategoriesToPrefs();
DCHECK(dismissed_providers_by_category_.empty());
}
@@ -192,6 +211,18 @@ void ContentSuggestionsService::OnNewSuggestions(
if (RegisterCategoryIfRequired(provider, category))
NotifyCategoryStatusChanged(category);
+ if (IsCategoryDismissed(category)) {
Marc Treib 2016/10/13 15:59:00 else if? If the category was just successfully reg
dgn 2016/10/14 21:20:28 Done.
+ // 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 +244,14 @@ void ContentSuggestionsService::OnCategoryStatusChanged(
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);
DCHECK_EQ(new_status, provider->GetCategoryStatus(category));
}
- NotifyCategoryStatusChanged(category);
+
+ if (!IsCategoryDismissed(category))
+ NotifyCategoryStatusChanged(category);
}
void ContentSuggestionsService::OnSuggestionInvalidated(
@@ -281,18 +311,36 @@ void ContentSuggestionsService::HistoryServiceBeingDeleted(
bool ContentSuggestionsService::RegisterCategoryIfRequired(
ContentSuggestionsProvider* provider,
Category category) {
+ // Search for the category in both the regular and dismissed lists.
auto it = providers_by_category_.find(category);
Marc Treib 2016/10/13 15:59:00 Can we early-out here if |it != providers_by_categ
dgn 2016/10/14 21:20:28 Done, also rewrote the function since it removes b
- if (it != providers_by_category_.end()) {
- DCHECK_EQ(it->second, provider);
- return false;
- }
-
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);
+
+ // We will need to register the provider for the category if it's absent from
+ // both. Note that the initialisation of dismissed categories registers them
+ // with |nullptr| for providers, we need to check for that too.
+ bool is_dismissed = dismissed_it != dismissed_providers_by_category_.end();
+ bool is_new = it == providers_by_category_.end() &&
+ (!is_dismissed || !dismissed_it->second);
Marc Treib 2016/10/13 15:59:00 Maybe |category_is_dismissed| and |provider_is_new
dgn 2016/10/14 21:20:28 Done.
+
+ if (is_new) {
+ if (is_dismissed) {
+ dismissed_it->second = provider;
+ return false;
+ }
+ RegisterCategoryInternal(category, provider);
+ } else {
+ DCHECK_EQ(is_dismissed ? dismissed_it->second : it->second, provider);
}
+ return is_new;
+}
+
+void ContentSuggestionsService::RegisterCategoryInternal(
+ Category category,
+ ContentSuggestionsProvider* provider) {
+ DCHECK(providers_by_category_.find(category) == providers_by_category_.end());
Marc Treib 2016/10/13 15:59:00 optional nit: base::ContainsKey
dgn 2016/10/14 21:20:28 Thanks! I was annoyed the STL doesn't provide anyt
+ DCHECK(!IsCategoryDismissed(category));
+
providers_by_category_[category] = provider;
categories_.push_back(category);
SortCategories();
@@ -300,7 +348,20 @@ bool ContentSuggestionsService::RegisterCategoryIfRequired(
suggestions_by_category_.insert(
std::make_pair(category, std::vector<ContentSuggestion>()));
}
- return true;
+}
+
+void ContentSuggestionsService::UnregisterCategory(
+ Category category,
+ ContentSuggestionsProvider* provider) {
+ if (IsCategoryDismissed(category))
Marc Treib 2016/10/13 15:59:00 Why?
dgn 2016/10/14 21:20:28 Because when OnCategoryStatusChanged() is called w
+ return;
+
+ auto providers_it = providers_by_category_.find(category);
+ DCHECK(providers_it != providers_by_category_.end());
+ DCHECK_EQ(provider, providers_it->second);
+ providers_by_category_.erase(providers_it);
+ categories_.erase(
+ std::find(categories_.begin(), categories_.end(), category));
}
bool ContentSuggestionsService::RemoveSuggestionByID(
@@ -350,4 +411,50 @@ void ContentSuggestionsService::SortCategories() {
});
}
+bool ContentSuggestionsService::IsCategoryDismissed(Category category) const {
+ return dismissed_providers_by_category_.find(category) !=
+ dismissed_providers_by_category_.end();
Marc Treib 2016/10/13 15:59:00 optional nit: base::ContainsKey
dgn 2016/10/14 21:20:28 Done.
+}
+
+void ContentSuggestionsService::RestoreDismissedCategory(Category category) {
+ auto dismissed_it = dismissed_providers_by_category_.find(category);
+ DCHECK(dismissed_it != dismissed_providers_by_category_.end());
+
+ // 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;
Marc Treib 2016/10/13 15:59:01 Can provider be null here? If not, DCHECK that?
dgn 2016/10/14 21:20:28 Good catch, it's possible, yes.
+ dismissed_providers_by_category_.erase(dismissed_it);
+
+ RegisterCategoryInternal(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 moved to this map.
Marc Treib 2016/10/13 15:59:00 nit: s/moved to/stored in/ ? "moved to" sounds lik
dgn 2016/10/14 21:20:28 Done.
+ 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

Powered by Google App Engine
This is Rietveld 408576698