summaryrefslogtreecommitdiff
path: root/chromium/components/ntp_snippets
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-17 13:57:45 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-19 13:44:40 +0000
commit6ec7b8da05d21a3878bd21c691b41e675d74bb1c (patch)
treeb87f250bc19413750b9bb9cdbf2da20ef5014820 /chromium/components/ntp_snippets
parentec02ee4181c49b61fce1c8fb99292dbb8139cc90 (diff)
downloadqtwebengine-chromium-6ec7b8da05d21a3878bd21c691b41e675d74bb1c.tar.gz
BASELINE: Update Chromium to 60.0.3112.70
Change-Id: I9911c2280a014d4632f254857876a395d4baed2d Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/components/ntp_snippets')
-rw-r--r--chromium/components/ntp_snippets/BUILD.gn2
-rw-r--r--chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc21
-rw-r--r--chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h8
-rw-r--r--chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider_unittest.cc7
-rw-r--r--chromium/components/ntp_snippets/category_rankers/category_ranker.h14
-rw-r--r--chromium/components/ntp_snippets/category_rankers/click_based_category_ranker.cc49
-rw-r--r--chromium/components/ntp_snippets/category_rankers/click_based_category_ranker.h2
-rw-r--r--chromium/components/ntp_snippets/category_rankers/constant_category_ranker.cc29
-rw-r--r--chromium/components/ntp_snippets/category_rankers/constant_category_ranker.h2
-rw-r--r--chromium/components/ntp_snippets/category_rankers/fake_category_ranker.cc5
-rw-r--r--chromium/components/ntp_snippets/category_rankers/fake_category_ranker.h1
-rw-r--r--chromium/components/ntp_snippets/category_rankers/mock_category_ranker.h1
-rw-r--r--chromium/components/ntp_snippets/content_suggestion.h8
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_metrics.cc21
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_metrics.h9
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_provider.h8
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_service.cc58
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_service.h10
-rw-r--r--chromium/components/ntp_snippets/features.cc28
-rw-r--r--chromium/components/ntp_snippets/features.h41
-rw-r--r--chromium/components/ntp_snippets/pref_names.cc21
-rw-r--r--chromium/components/ntp_snippets/pref_names.h30
-rw-r--r--chromium/components/ntp_snippets/reading_list/reading_list_distillation_state_util.cc50
-rw-r--r--chromium/components/ntp_snippets/reading_list/reading_list_distillation_state_util.h23
-rw-r--r--chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.cc12
-rwxr-xr-xchromium/components/ntp_snippets/remote/fetch.py4
-rw-r--r--chromium/components/ntp_snippets/remote/json_request.cc5
-rw-r--r--chromium/components/ntp_snippets/remote/json_request_unittest.cc26
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_fetcher_unittest.cc10
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc90
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.h5
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc202
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.cc183
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.h13
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc64
-rw-r--r--chromium/components/ntp_snippets/user_classifier.cc8
36 files changed, 703 insertions, 367 deletions
diff --git a/chromium/components/ntp_snippets/BUILD.gn b/chromium/components/ntp_snippets/BUILD.gn
index 0cf1874adc8..54a66cf3d0e 100644
--- a/chromium/components/ntp_snippets/BUILD.gn
+++ b/chromium/components/ntp_snippets/BUILD.gn
@@ -47,8 +47,6 @@ static_library("ntp_snippets") {
"pref_names.h",
"pref_util.cc",
"pref_util.h",
- "reading_list/reading_list_distillation_state_util.cc",
- "reading_list/reading_list_distillation_state_util.h",
"reading_list/reading_list_suggestions_provider.cc",
"reading_list/reading_list_suggestions_provider.h",
"remote/json_request.cc",
diff --git a/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc b/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc
index 436e8bcee05..9b0e2df80d3 100644
--- a/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc
+++ b/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc
@@ -18,9 +18,6 @@
#include "components/ntp_snippets/category.h"
#include "components/ntp_snippets/content_suggestion.h"
#include "components/ntp_snippets/features.h"
-#include "components/ntp_snippets/pref_names.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
#include "components/strings/grit/components_strings.h"
#include "components/variations/variations_associated_data.h"
#include "ui/base/l10n/l10n_util.h"
@@ -34,17 +31,13 @@ namespace ntp_snippets {
namespace {
const int kMaxBookmarks = 10;
-const int kMaxBookmarkAgeInDays = 42;
+const int kMaxBookmarkAgeInDays = 7;
const char* kMaxBookmarksParamName = "bookmarks_max_count";
const char* kMaxBookmarkAgeInDaysParamName = "bookmarks_max_age_in_days";
const char* kConsiderDesktopVisitsParamName =
"bookmarks_consider_desktop_visits";
-// TODO(treib,jkrcal): Remove this after M57.
-const char kDeprecatedBookmarksFirstM54StartPref[] =
- "ntp_suggestions.bookmarks.first_M54_start";
-
// Any bookmark created or visited after this time will be considered recent.
// Note that bookmarks can be shown that do not meet this threshold.
base::Time GetThresholdTime() {
@@ -64,15 +57,14 @@ int GetMaxCount() {
bool AreDesktopVisitsConsidered() {
return variations::GetVariationParamByFeatureAsBool(
ntp_snippets::kBookmarkSuggestionsFeature,
- kConsiderDesktopVisitsParamName, false);
+ kConsiderDesktopVisitsParamName, true);
}
} // namespace
BookmarkSuggestionsProvider::BookmarkSuggestionsProvider(
ContentSuggestionsProvider::Observer* observer,
- bookmarks::BookmarkModel* bookmark_model,
- PrefService* pref_service)
+ bookmarks::BookmarkModel* bookmark_model)
: ContentSuggestionsProvider(observer),
category_status_(CategoryStatus::AVAILABLE_LOADING),
provided_category_(
@@ -82,7 +74,6 @@ BookmarkSuggestionsProvider::BookmarkSuggestionsProvider(
end_of_list_last_visit_date_(GetThresholdTime()),
consider_bookmark_visits_from_desktop_(AreDesktopVisitsConsidered()) {
observer->OnCategoryStatusChanged(this, provided_category_, category_status_);
- pref_service->ClearPref(kDeprecatedBookmarksFirstM54StartPref);
bookmark_model_->AddObserver(this);
FetchBookmarks();
}
@@ -91,12 +82,6 @@ BookmarkSuggestionsProvider::~BookmarkSuggestionsProvider() {
bookmark_model_->RemoveObserver(this);
}
-// static
-void BookmarkSuggestionsProvider::RegisterProfilePrefs(
- PrefRegistrySimple* registry) {
- registry->RegisterInt64Pref(kDeprecatedBookmarksFirstM54StartPref, 0);
-}
-
////////////////////////////////////////////////////////////////////////////////
// Private methods
diff --git a/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h b/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h
index 64cd6e25d1a..404c8d6ada2 100644
--- a/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h
+++ b/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h
@@ -15,9 +15,6 @@
#include "components/ntp_snippets/category_status.h"
#include "components/ntp_snippets/content_suggestions_provider.h"
-class PrefRegistrySimple;
-class PrefService;
-
namespace ntp_snippets {
// Provides content suggestions from the bookmarks model.
@@ -25,12 +22,9 @@ class BookmarkSuggestionsProvider : public ContentSuggestionsProvider,
public bookmarks::BookmarkModelObserver {
public:
BookmarkSuggestionsProvider(ContentSuggestionsProvider::Observer* observer,
- bookmarks::BookmarkModel* bookmark_model,
- PrefService* pref_service);
+ bookmarks::BookmarkModel* bookmark_model);
~BookmarkSuggestionsProvider() override;
- static void RegisterProfilePrefs(PrefRegistrySimple* registry);
-
private:
// ContentSuggestionsProvider implementation.
CategoryStatus GetCategoryStatus(Category category) override;
diff --git a/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider_unittest.cc b/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider_unittest.cc
index 92682d579b7..fda7b18c941 100644
--- a/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider_unittest.cc
+++ b/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider_unittest.cc
@@ -18,7 +18,6 @@
#include "components/ntp_snippets/bookmarks/bookmark_last_visit_utils.h"
#include "components/ntp_snippets/category.h"
#include "components/ntp_snippets/mock_content_suggestions_provider_observer.h"
-#include "components/prefs/testing_pref_service.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -53,15 +52,13 @@ class BookmarkSuggestionsProviderTest : public ::testing::Test {
_, Category::FromKnownCategory(KnownCategories::BOOKMARKS),
CategoryStatus::AVAILABLE))
.RetiresOnSaturation();
- BookmarkSuggestionsProvider::RegisterProfilePrefs(test_prefs_.registry());
- provider_ = base::MakeUnique<BookmarkSuggestionsProvider>(
- &observer_, model_.get(), &test_prefs_);
+ provider_ =
+ base::MakeUnique<BookmarkSuggestionsProvider>(&observer_, model_.get());
}
protected:
std::unique_ptr<bookmarks::BookmarkModel> model_;
StrictMock<MockContentSuggestionsProviderObserver> observer_;
- TestingPrefServiceSimple test_prefs_;
std::unique_ptr<BookmarkSuggestionsProvider> provider_;
};
diff --git a/chromium/components/ntp_snippets/category_rankers/category_ranker.h b/chromium/components/ntp_snippets/category_rankers/category_ranker.h
index aa19c57d668..89b01246f64 100644
--- a/chromium/components/ntp_snippets/category_rankers/category_ranker.h
+++ b/chromium/components/ntp_snippets/category_rankers/category_ranker.h
@@ -5,6 +5,9 @@
#ifndef COMPONENTS_NTP_SNIPPETS_CATEGORY_RANKERS_CATEGORY_RANKER_H_
#define COMPONENTS_NTP_SNIPPETS_CATEGORY_RANKERS_CATEGORY_RANKER_H_
+#include <string>
+#include <vector>
+
#include "base/time/time.h"
#include "components/ntp_snippets/category.h"
@@ -39,6 +42,17 @@ class CategoryRanker {
virtual void InsertCategoryAfterIfNecessary(Category category_to_insert,
Category anchor) = 0;
+ struct DebugDataItem {
+ std::string label;
+ std::string content;
+ DebugDataItem(const std::string& label, const std::string& content)
+ : label(label), content(content) {}
+ };
+
+ // Returns DebugData in form of pairs of strings (label; content),
+ // e.g. describing internal state or parameter values.
+ virtual std::vector<DebugDataItem> GetDebugData() = 0;
+
// Feedback data from the user to update the ranking.
// Called whenever a suggestion is opened by the user.
diff --git a/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker.cc b/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker.cc
index 62e2ad711b5..1b060e63eb6 100644
--- a/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker.cc
+++ b/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker.cc
@@ -10,6 +10,7 @@
#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
#include "base/values.h"
#include "components/ntp_snippets/category_rankers/constant_category_ranker.h"
#include "components/ntp_snippets/content_suggestions_metrics.h"
@@ -131,6 +132,14 @@ base::Optional<Category> GetPromotedCategoryFromVariations() {
return Category::FromIDValue(category_id);
}
+std::string GetOptionalCategoryAsString(
+ const base::Optional<Category>& optional_category) {
+ if (optional_category.has_value()) {
+ return base::IntToString(optional_category->id());
+ }
+ return "None";
+}
+
} // namespace
ClickBasedCategoryRanker::ClickBasedCategoryRanker(
@@ -264,6 +273,46 @@ void ClickBasedCategoryRanker::InsertCategoryAfterIfNecessary(
/*after=*/true);
}
+std::vector<CategoryRanker::DebugDataItem>
+ClickBasedCategoryRanker::GetDebugData() {
+ std::vector<CategoryRanker::DebugDataItem> result;
+ result.push_back(
+ CategoryRanker::DebugDataItem("Type", "ClickBasedCategoryRanker"));
+
+ std::string initial_order_type;
+ CategoryOrderChoice choice = GetSelectedCategoryOrder();
+ if (choice == CategoryOrderChoice::GENERAL) {
+ initial_order_type = "GENERAL";
+ }
+ if (choice == CategoryOrderChoice::EMERGING_MARKETS_ORIENTED) {
+ initial_order_type = "EMERGING_MARKETS_ORIENTED;";
+ }
+ result.push_back(
+ CategoryRanker::DebugDataItem("Initial order type", initial_order_type));
+
+ std::vector<std::string> category_strings;
+ for (const auto& ranked_category : ordered_categories_) {
+ category_strings.push_back(base::ReplaceStringPlaceholders(
+ "($1; $2)",
+ {base::IntToString(ranked_category.category.id()),
+ base::IntToString(ranked_category.clicks)},
+ /*offsets=*/nullptr));
+ }
+ result.push_back(
+ CategoryRanker::DebugDataItem("Current order (with click counts)",
+ base::JoinString(category_strings, ", ")));
+
+ result.push_back(CategoryRanker::DebugDataItem(
+ "Actual promoted category",
+ GetOptionalCategoryAsString(promoted_category_)));
+
+ result.push_back(CategoryRanker::DebugDataItem(
+ "Raw promoted category from variations",
+ GetOptionalCategoryAsString(GetPromotedCategoryFromVariations())));
+
+ return result;
+}
+
void ClickBasedCategoryRanker::OnSuggestionOpened(Category category) {
if (!ContainsCategory(category)) {
LOG(DFATAL) << "The category with ID " << category.id()
diff --git a/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker.h b/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker.h
index 06bd846107f..1c69ec913d7 100644
--- a/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker.h
+++ b/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker.h
@@ -6,6 +6,7 @@
#define COMPONENTS_NTP_SNIPPETS_CATEGORY_RANKERS_CLICK_BASED_CATEGORY_RANKER_H_
#include <memory>
+#include <string>
#include <vector>
#include "base/optional.h"
@@ -40,6 +41,7 @@ class ClickBasedCategoryRanker : public CategoryRanker {
Category anchor) override;
void InsertCategoryAfterIfNecessary(Category category_to_insert,
Category anchor) override;
+ std::vector<CategoryRanker::DebugDataItem> GetDebugData() override;
void OnSuggestionOpened(Category category) override;
void OnCategoryDismissed(Category category) override;
diff --git a/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.cc b/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.cc
index 828cd317e5d..d68fe9104d4 100644
--- a/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.cc
+++ b/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.cc
@@ -5,6 +5,8 @@
#include "components/ntp_snippets/category_rankers/constant_category_ranker.h"
#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
#include "components/ntp_snippets/features.h"
namespace ntp_snippets {
@@ -75,6 +77,33 @@ void ConstantCategoryRanker::InsertCategoryAfterIfNecessary(
AppendCategoryIfNecessary(category_to_insert);
}
+std::vector<CategoryRanker::DebugDataItem>
+ConstantCategoryRanker::GetDebugData() {
+ std::vector<CategoryRanker::DebugDataItem> result;
+ result.push_back(
+ CategoryRanker::DebugDataItem("Type", "ConstantCategoryRanker"));
+
+ std::string initial_order_type;
+ CategoryOrderChoice choice = GetSelectedCategoryOrder();
+ if (choice == CategoryOrderChoice::GENERAL) {
+ initial_order_type = "GENERAL";
+ }
+ if (choice == CategoryOrderChoice::EMERGING_MARKETS_ORIENTED) {
+ initial_order_type = "EMERGING_MARKETS_ORIENTED;";
+ }
+ result.push_back(
+ CategoryRanker::DebugDataItem("Initial order type", initial_order_type));
+
+ std::vector<std::string> category_strings;
+ for (Category category : ordered_categories_) {
+ category_strings.push_back(base::IntToString(category.id()));
+ }
+ result.push_back(CategoryRanker::DebugDataItem(
+ "Current order", base::JoinString(category_strings, ", ")));
+
+ return result;
+}
+
void ConstantCategoryRanker::OnSuggestionOpened(Category category) {
// Ignored. The order is constant.
}
diff --git a/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.h b/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.h
index 8e4417e859a..b3a129ec4e7 100644
--- a/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.h
+++ b/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_NTP_SNIPPETS_SECTION_RANKERS_CONSTANT_SECTION_RANKER_H_
#define COMPONENTS_NTP_SNIPPETS_SECTION_RANKERS_CONSTANT_SECTION_RANKER_H_
+#include <string>
#include <vector>
#include "base/time/time.h"
@@ -31,6 +32,7 @@ class ConstantCategoryRanker : public CategoryRanker {
Category anchor) override;
void InsertCategoryAfterIfNecessary(Category category_to_insert,
Category anchor) override;
+ std::vector<CategoryRanker::DebugDataItem> GetDebugData() override;
void OnSuggestionOpened(Category category) override;
void OnCategoryDismissed(Category category) override;
diff --git a/chromium/components/ntp_snippets/category_rankers/fake_category_ranker.cc b/chromium/components/ntp_snippets/category_rankers/fake_category_ranker.cc
index 94739a7b525..42ce8bc9dab 100644
--- a/chromium/components/ntp_snippets/category_rankers/fake_category_ranker.cc
+++ b/chromium/components/ntp_snippets/category_rankers/fake_category_ranker.cc
@@ -42,6 +42,11 @@ void FakeCategoryRanker::InsertCategoryAfterIfNecessary(
// Ignored.
}
+std::vector<CategoryRanker::DebugDataItem> FakeCategoryRanker::GetDebugData() {
+ // Ignored.
+ return std::vector<CategoryRanker::DebugDataItem>();
+}
+
void FakeCategoryRanker::OnSuggestionOpened(Category category) {
// Ignored.
}
diff --git a/chromium/components/ntp_snippets/category_rankers/fake_category_ranker.h b/chromium/components/ntp_snippets/category_rankers/fake_category_ranker.h
index 9b5e37659ff..dedba15bf66 100644
--- a/chromium/components/ntp_snippets/category_rankers/fake_category_ranker.h
+++ b/chromium/components/ntp_snippets/category_rankers/fake_category_ranker.h
@@ -31,6 +31,7 @@ class FakeCategoryRanker : public CategoryRanker {
Category anchor) override;
void InsertCategoryAfterIfNecessary(Category category_to_insert,
Category anchor) override;
+ std::vector<CategoryRanker::DebugDataItem> GetDebugData() override;
void OnSuggestionOpened(Category category) override;
void OnCategoryDismissed(Category category) override;
diff --git a/chromium/components/ntp_snippets/category_rankers/mock_category_ranker.h b/chromium/components/ntp_snippets/category_rankers/mock_category_ranker.h
index 2238aeea7e7..6dbed913c8e 100644
--- a/chromium/components/ntp_snippets/category_rankers/mock_category_ranker.h
+++ b/chromium/components/ntp_snippets/category_rankers/mock_category_ranker.h
@@ -24,6 +24,7 @@ class MockCategoryRanker : public CategoryRanker {
void(Category category_to_insert, Category anchor));
MOCK_METHOD2(InsertCategoryAfterIfNecessary,
void(Category category_to_insert, Category anchor));
+ MOCK_METHOD0(GetDebugData, std::vector<CategoryRanker::DebugDataItem>());
MOCK_METHOD1(OnSuggestionOpened, void(Category category));
MOCK_METHOD1(OnCategoryDismissed, void(Category Category));
};
diff --git a/chromium/components/ntp_snippets/content_suggestion.h b/chromium/components/ntp_snippets/content_suggestion.h
index 5bc647e4cda..1b70c38fbd1 100644
--- a/chromium/components/ntp_snippets/content_suggestion.h
+++ b/chromium/components/ntp_snippets/content_suggestion.h
@@ -49,14 +49,8 @@ struct RecentTabSuggestionExtra {
// ReadingListSuggestionExtra contains additional data which is only available
// for Reading List suggestions.
struct ReadingListSuggestionExtra {
- // State of the distillation a suggestion. This is the meaningful extract of
- // ReadingListEntry::DistillationState for the suggestions. It is duplicated
- // here to avoid a dependence on ReadingList.
- enum class ReadingListSuggestionDistilledState { PENDING, SUCCESS, FAILURE };
-
// State of the distillation of the suggestion.
- ReadingListSuggestionDistilledState distilled_state =
- ReadingListSuggestionDistilledState::PENDING;
+ bool distilled = false;
// URL of the page whose favicon should be displayed for this suggestion.
GURL favicon_page_url;
};
diff --git a/chromium/components/ntp_snippets/content_suggestions_metrics.cc b/chromium/components/ntp_snippets/content_suggestions_metrics.cc
index 5d2d4afe9af..348a555694e 100644
--- a/chromium/components/ntp_snippets/content_suggestions_metrics.cc
+++ b/chromium/components/ntp_snippets/content_suggestions_metrics.cc
@@ -25,6 +25,8 @@ const int kMaxCategories = 10;
const char kHistogramCountOnNtpOpened[] =
"NewTabPage.ContentSuggestions.CountOnNtpOpened";
+const char kHistogramSectionCountOnNtpOpened[] =
+ "NewTabPage.ContentSuggestions.SectionCountOnNtpOpened";
const char kHistogramShown[] = "NewTabPage.ContentSuggestions.Shown";
const char kHistogramShownAge[] = "NewTabPage.ContentSuggestions.ShownAge";
const char kHistogramShownScore[] =
@@ -212,7 +214,8 @@ void RecordContentSuggestionsUsage() {
} // namespace
void OnPageShown(
- const std::vector<std::pair<Category, int>>& suggestions_per_category) {
+ const std::vector<std::pair<Category, int>>& suggestions_per_category,
+ int visible_categories_count) {
int suggestions_total = 0;
for (const std::pair<Category, int>& item : suggestions_per_category) {
LogCategoryHistogramPosition(kHistogramCountOnNtpOpened, item.first,
@@ -221,6 +224,8 @@ void OnPageShown(
}
UMA_HISTOGRAM_EXACT_LINEAR(kHistogramCountOnNtpOpened, suggestions_total,
kMaxSuggestionsTotal);
+ UMA_HISTOGRAM_EXACT_LINEAR(kHistogramSectionCountOnNtpOpened,
+ visible_categories_count, kMaxCategories);
}
void OnSuggestionShown(int global_position,
@@ -292,6 +297,8 @@ void OnSuggestionOpened(int global_position,
if (category.IsKnownCategory(KnownCategories::ARTICLES)) {
RecordContentSuggestionsUsage();
}
+
+ base::RecordAction(base::UserMetricsAction("Suggestions.Content.Opened"));
}
void OnSuggestionMenuOpened(int global_position,
@@ -366,5 +373,17 @@ void RecordRemoteSuggestionsProviderState(bool enabled) {
"NewTabPage.ContentSuggestions.Preferences.RemoteSuggestions", enabled);
}
+void RecordContentSuggestionDismissed() {
+ base::RecordAction(base::UserMetricsAction("Suggestions.Content.Dismissed"));
+}
+
+void RecordCategoryDismissed() {
+ base::RecordAction(base::UserMetricsAction("Suggestions.Category.Dismissed"));
+}
+
+void RecordFetchAction() {
+ base::RecordAction(base::UserMetricsAction("Suggestions.Category.Fetch"));
+}
+
} // namespace metrics
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/content_suggestions_metrics.h b/chromium/components/ntp_snippets/content_suggestions_metrics.h
index a2f04e5668d..e31b7713633 100644
--- a/chromium/components/ntp_snippets/content_suggestions_metrics.h
+++ b/chromium/components/ntp_snippets/content_suggestions_metrics.h
@@ -16,7 +16,8 @@ namespace ntp_snippets {
namespace metrics {
void OnPageShown(
- const std::vector<std::pair<Category, int>>& suggestions_per_category);
+ const std::vector<std::pair<Category, int>>& suggestions_per_category,
+ int visible_categories_count);
// Should only be called once per NTP for each suggestion.
void OnSuggestionShown(int global_position,
@@ -60,6 +61,12 @@ void OnCategoryDismissed(Category category);
void RecordRemoteSuggestionsProviderState(bool enabled);
+void RecordContentSuggestionDismissed();
+
+void RecordCategoryDismissed();
+
+void RecordFetchAction();
+
} // namespace metrics
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/content_suggestions_provider.h b/chromium/components/ntp_snippets/content_suggestions_provider.h
index 8c485dfd5a0..3fc37b01525 100644
--- a/chromium/components/ntp_snippets/content_suggestions_provider.h
+++ b/chromium/components/ntp_snippets/content_suggestions_provider.h
@@ -97,9 +97,11 @@ class ContentSuggestionsProvider {
// Fetches more suggestions for the given category. The new suggestions
// will not include any suggestion of the |known_suggestion_ids| sets.
- // The given |callback| is called with these suggestions, along with all
- // existing suggestions. It has to be invoked exactly once as the front-end
- // might wait for its completion.
+ // As a result of this call, the provider:
+ // - should call the |callback| with these additional suggestions (exactly
+ // once as the front-end might wait for its completion);
+ // - should *not* notify its Observer by OnNewSuggestions() with these
+ // additional suggestions.
virtual void Fetch(const Category& category,
const std::set<std::string>& known_suggestion_ids,
const FetchDoneCallback& callback) = 0;
diff --git a/chromium/components/ntp_snippets/content_suggestions_service.cc b/chromium/components/ntp_snippets/content_suggestions_service.cc
index de7ab3ff14f..71f323594d2 100644
--- a/chromium/components/ntp_snippets/content_suggestions_service.cc
+++ b/chromium/components/ntp_snippets/content_suggestions_service.cc
@@ -20,6 +20,7 @@
#include "components/favicon/core/large_icon_service.h"
#include "components/favicon_base/fallback_icon_style.h"
#include "components/favicon_base/favicon_types.h"
+#include "components/ntp_snippets/content_suggestions_metrics.h"
#include "components/ntp_snippets/pref_names.h"
#include "components/ntp_snippets/remote/remote_suggestions_provider.h"
#include "components/prefs/pref_registry_simple.h"
@@ -169,16 +170,9 @@ void ContentSuggestionsService::FetchSuggestionFavicon(
return;
}
- // TODO(jkrcal): Create a general wrapper function in LargeIconService that
- // does handle the get-from-cache-and-fallback-to-google-server functionality
- // in one shot (for all clients that do not need to react in between).
- large_icon_service_->GetLargeIconImageOrFallbackStyle(
- domain_with_favicon, minimum_size_in_pixel, desired_size_in_pixel,
- base::Bind(&ContentSuggestionsService::OnGetFaviconFromCacheFinished,
- base::Unretained(this), domain_with_favicon,
- minimum_size_in_pixel, desired_size_in_pixel, callback,
- /*continue_to_google_server=*/true),
- &favicons_task_tracker_);
+ GetFaviconFromCache(domain_with_favicon, minimum_size_in_pixel,
+ desired_size_in_pixel, callback,
+ /*continue_to_google_server=*/true);
}
GURL ContentSuggestionsService::GetFaviconDomain(
@@ -204,6 +198,26 @@ GURL ContentSuggestionsService::GetFaviconDomain(
return GURL();
}
+void ContentSuggestionsService::GetFaviconFromCache(
+ const GURL& publisher_url,
+ int minimum_size_in_pixel,
+ int desired_size_in_pixel,
+ const ImageFetchedCallback& callback,
+ bool continue_to_google_server) {
+ // TODO(jkrcal): Create a general wrapper function in LargeIconService that
+ // does handle the get-from-cache-and-fallback-to-google-server functionality
+ // in one shot (for all clients that do not need to react in between).
+
+ // Use desired_size = 0 for getting the icon from the cache (so that the icon
+ // is not poorly rescaled by LargeIconService).
+ large_icon_service_->GetLargeIconImageOrFallbackStyle(
+ publisher_url, minimum_size_in_pixel, /*desired_size_in_pixel=*/0,
+ base::Bind(&ContentSuggestionsService::OnGetFaviconFromCacheFinished,
+ base::Unretained(this), publisher_url, minimum_size_in_pixel,
+ desired_size_in_pixel, callback, continue_to_google_server),
+ &favicons_task_tracker_);
+}
+
void ContentSuggestionsService::OnGetFaviconFromCacheFinished(
const GURL& publisher_url,
int minimum_size_in_pixel,
@@ -233,9 +247,13 @@ void ContentSuggestionsService::OnGetFaviconFromCacheFinished(
}
// Try to fetch the favicon from a Google favicon server.
+ // TODO(jkrcal): Currently used only for Articles for you which have public
+ // URLs. Let the provider decide whether |publisher_url| may be private or
+ // not.
large_icon_service_
->GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
- publisher_url, minimum_size_in_pixel,
+ publisher_url, minimum_size_in_pixel, desired_size_in_pixel,
+ /*may_page_url_be_private=*/false,
base::Bind(
&ContentSuggestionsService::OnGetFaviconFromGoogleServerFinished,
base::Unretained(this), publisher_url, minimum_size_in_pixel,
@@ -254,14 +272,9 @@ void ContentSuggestionsService::OnGetFaviconFromGoogleServerFinished(
return;
}
- // Get the freshly downloaded icon from the cache.
- large_icon_service_->GetLargeIconImageOrFallbackStyle(
- publisher_url, minimum_size_in_pixel, desired_size_in_pixel,
- base::Bind(&ContentSuggestionsService::OnGetFaviconFromCacheFinished,
- base::Unretained(this), publisher_url, minimum_size_in_pixel,
- desired_size_in_pixel, callback,
- /*continue_to_google_server=*/false),
- &favicons_task_tracker_);
+ GetFaviconFromCache(publisher_url, minimum_size_in_pixel,
+ desired_size_in_pixel, callback,
+ /*continue_to_google_server=*/false);
}
void ContentSuggestionsService::ClearHistory(
@@ -324,6 +337,9 @@ void ContentSuggestionsService::DismissSuggestion(
<< " for unavailable category " << suggestion_id.category();
return;
}
+
+ metrics::RecordContentSuggestionDismissed();
+
providers_by_category_[suggestion_id.category()]->DismissSuggestion(
suggestion_id);
@@ -339,6 +355,8 @@ void ContentSuggestionsService::DismissCategory(Category category) {
return;
}
+ metrics::RecordCategoryDismissed();
+
ContentSuggestionsProvider* provider = providers_it->second;
UnregisterCategory(category, provider);
@@ -382,6 +400,8 @@ void ContentSuggestionsService::Fetch(
return;
}
+ metrics::RecordFetchAction();
+
providers_it->second->Fetch(category, known_suggestion_ids, callback);
}
diff --git a/chromium/components/ntp_snippets/content_suggestions_service.h b/chromium/components/ntp_snippets/content_suggestions_service.h
index 308e4dbe69d..40c442bc6bb 100644
--- a/chromium/components/ntp_snippets/content_suggestions_service.h
+++ b/chromium/components/ntp_snippets/content_suggestions_service.h
@@ -15,6 +15,7 @@
#include "base/observer_list.h"
#include "base/optional.h"
#include "base/scoped_observer.h"
+#include "base/supports_user_data.h"
#include "base/task/cancelable_task_tracker.h"
#include "base/time/time.h"
#include "components/history/core/browser/history_service.h"
@@ -47,6 +48,7 @@ class RemoteSuggestionsProvider;
// Retrieves suggestions from a number of ContentSuggestionsProviders and serves
// them grouped into categories. There can be at most one provider per category.
class ContentSuggestionsService : public KeyedService,
+ public base::SupportsUserData,
public ContentSuggestionsProvider::Observer,
public SigninManagerBase::Observer,
public history::HistoryServiceObserver {
@@ -330,6 +332,14 @@ class ContentSuggestionsService : public KeyedService,
// Get the domain of the suggestion suitable for fetching the favicon.
GURL GetFaviconDomain(const ContentSuggestion::ID& suggestion_id);
+
+ // Initiate the fetch of a favicon from the local cache.
+ void GetFaviconFromCache(const GURL& publisher_url,
+ int minimum_size_in_pixel,
+ int desired_size_in_pixel,
+ const ImageFetchedCallback& callback,
+ bool continue_to_google_server);
+
// Callbacks for fetching favicons.
void OnGetFaviconFromCacheFinished(
const GURL& publisher_url,
diff --git a/chromium/components/ntp_snippets/features.cc b/chromium/components/ntp_snippets/features.cc
index 0b90a4271f1..6910f402873 100644
--- a/chromium/components/ntp_snippets/features.cc
+++ b/chromium/components/ntp_snippets/features.cc
@@ -13,6 +13,20 @@
namespace ntp_snippets {
+// Keep sorted, and keep nullptr at the end.
+const base::Feature*(kAllFeatures[]) = {&kArticleSuggestionsFeature,
+ &kBookmarkSuggestionsFeature,
+ &kCategoryOrder,
+ &kCategoryRanker,
+ &kForeignSessionsSuggestionsFeature,
+ &kIncreasedVisibility,
+ &kNotificationsFeature,
+ &kPhysicalWebPageSuggestionsFeature,
+ &kPreferAmpUrlsFeature,
+ &kPublisherFaviconsFromNewServerFeature,
+ &kRecentOfflineTabSuggestionsFeature,
+ nullptr};
+
const base::Feature kArticleSuggestionsFeature{
"NTPArticleSuggestions", base::FEATURE_ENABLED_BY_DEFAULT};
@@ -113,4 +127,18 @@ CategoryOrderChoice GetSelectedCategoryOrder() {
return CategoryOrderChoice::GENERAL;
}
+const base::Feature kNotificationsFeature = {"ContentSuggestionsNotifications",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+const char kNotificationsPriorityParam[] = "priority";
+const char kNotificationsTextParam[] = "text";
+const char kNotificationsTextValuePublisher[] = "publisher";
+const char kNotificationsTextValueSnippet[] = "snippet";
+const char kNotificationsTextValueAndMore[] = "and_more";
+const char kNotificationsKeepWhenFrontmostParam[] =
+ "keep_notification_when_frontmost";
+const char kNotificationsOpenToNTPParam[] = "open_to_ntp";
+const char kNotificationsDailyLimit[] = "daily_limit";
+const char kNotificationsIgnoredLimitParam[] = "ignored_limit";
+
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/features.h b/chromium/components/ntp_snippets/features.h
index 8832aed5502..9946e7c2d0a 100644
--- a/chromium/components/ntp_snippets/features.h
+++ b/chromium/components/ntp_snippets/features.h
@@ -18,6 +18,14 @@ class Clock;
namespace ntp_snippets {
+//
+// Null-terminated list of all features related to content suggestions.
+//
+// If you add a base::Feature below, you must add it to this list. It is used in
+// internal pages to list relevant parameters and settings.
+//
+extern const base::Feature*(kAllFeatures[]);
+
// Features to turn individual providers/categories on/off.
// TODO(jkrcal): Rename to kRemoteSuggestionsFeature.
extern const base::Feature kArticleSuggestionsFeature;
@@ -72,6 +80,39 @@ enum class CategoryOrderChoice {
// Returns which category order to use according to kCategoryOrder feature.
CategoryOrderChoice GetSelectedCategoryOrder();
+// Enables and configures notifications for content suggestions on Android.
+extern const base::Feature kNotificationsFeature;
+
+// An integer. The priority of the notification, ranging from -2 (PRIORITY_MIN)
+// to 2 (PRIORITY_MAX). Vibrates and makes sound if >= 0.
+extern const char kNotificationsPriorityParam[];
+constexpr int kNotificationsDefaultPriority = -1;
+
+// "publisher": use article's publisher as notification's text (default).
+// "snippet": use article's snippet as notification's text.
+// "and_more": use "From $1. Read this article and $2 more." as text.
+extern const char kNotificationsTextParam[];
+extern const char kNotificationsTextValuePublisher[];
+extern const char kNotificationsTextValueSnippet[];
+extern const char kNotificationsTextValueAndMore[];
+
+// "true": when Chrome becomes frontmost, leave notifications open.
+// "false": automatically dismiss notification when Chrome becomes frontmost.
+extern const char kNotificationsKeepWhenFrontmostParam[];
+
+// "true": notifications link to chrome://newtab, with appropriate text.
+// "false": notifications link to URL of notifying article.
+extern const char kNotificationsOpenToNTPParam[];
+
+// An integer. The maximum number of notifications that will be shown in 1 day.
+extern const char kNotificationsDailyLimit[];
+constexpr int kNotificationsDefaultDailyLimit = 1;
+
+// An integer. The number of notifications that can be ignored. If the user
+// ignores this many notifications or more, we stop sending them.
+extern const char kNotificationsIgnoredLimitParam[];
+constexpr int kNotificationsIgnoredDefaultLimit = 3;
+
} // namespace ntp_snippets
#endif // COMPONENTS_NTP_SNIPPETS_FEATURES_H_
diff --git a/chromium/components/ntp_snippets/pref_names.cc b/chromium/components/ntp_snippets/pref_names.cc
index fb5582a6725..bea67c36392 100644
--- a/chromium/components/ntp_snippets/pref_names.cc
+++ b/chromium/components/ntp_snippets/pref_names.cc
@@ -13,18 +13,25 @@ const char kRemoteSuggestionCategories[] = "ntp_snippets.remote_categories";
const char kSnippetLastFetchAttempt[] = "ntp_snippets.last_fetch_attempt";
-const char kSnippetSoftFetchingIntervalWifi[] =
- "ntp_snippets.soft_fetching_interval_wifi";
-
-const char kSnippetSoftFetchingIntervalFallback[] =
- "ntp_snippets.soft_fetching_interval_fallback";
-
+// For backwards compatibility, we do not rename the "fetching_" prefs (should
+// be "persistent_fetching_").
const char kSnippetPersistentFetchingIntervalWifi[] =
"ntp_snippets.fetching_interval_wifi";
-
const char kSnippetPersistentFetchingIntervalFallback[] =
"ntp_snippets.fetching_interval_fallback";
+const char kSnippetStartupFetchingIntervalWifi[] =
+ "ntp_snippets.startup_fetching_interval_wifi";
+const char kSnippetStartupFetchingIntervalFallback[] =
+ "ntp_snippets.startup_fetching_interval_fallback";
+
+// For backwards compatibility, we do not rename the "soft_fetching_" prefs
+// (should be "shown_fetching_").
+const char kSnippetShownFetchingIntervalWifi[] =
+ "ntp_snippets.soft_fetching_interval_wifi";
+const char kSnippetShownFetchingIntervalFallback[] =
+ "ntp_snippets.soft_fetching_interval_fallback";
+
const char kSnippetFetcherRequestCount[] =
"ntp.request_throttler.suggestion_fetcher.count";
const char kSnippetFetcherInteractiveRequestCount[] =
diff --git a/chromium/components/ntp_snippets/pref_names.h b/chromium/components/ntp_snippets/pref_names.h
index 9826eb9e9ca..fe3e198c83e 100644
--- a/chromium/components/ntp_snippets/pref_names.h
+++ b/chromium/components/ntp_snippets/pref_names.h
@@ -18,21 +18,25 @@ extern const char kRemoteSuggestionCategories[];
// The pref name for the last time when a background fetch was attempted.
extern const char kSnippetLastFetchAttempt[];
-// The pref name for the currently applied minimal interval between two
-// successive soft background fetches that react to user activity (such as
-// opening Chrome) when there is a WiFi connectivity.
-extern const char kSnippetSoftFetchingIntervalWifi[];
-// The pref name for the currently applied minimal interval between two
-// successive soft background fetches that react to user activity (such as
-// opening Chrome) when there is no WiFi connectivity.
-extern const char kSnippetSoftFetchingIntervalFallback[];
-
-// The pref name for the currently-scheduled background fetching interval when
-// there is WiFi connectivity.
+
+// Pref names for minimal intervals between two successive background fetches.
+//
+// The prefs store *currently applied* minimal intervals. For each trigger type
+// there are two intervals stored in prefs:
+// - "Wifi" for situations with Wifi / unmetered network connectivity, and
+// - "Fallback" for situations with only non-Wifi / metered network.
+// We check "meteredness" of the current network only on platforms that support
+// that, notably Android; we use WiFi as the proxy of being unmetered elsewhere.
+//
+// Intervals for trigger type 1: wake-up of the persistent scheduler.
extern const char kSnippetPersistentFetchingIntervalWifi[];
-// The pref name for the currently-scheduled background fetching interval when
-// there is no WiFi connectivity.
extern const char kSnippetPersistentFetchingIntervalFallback[];
+// Intervals for trigger type 2: browser started-up (both cold and warm start).
+extern const char kSnippetStartupFetchingIntervalWifi[];
+extern const char kSnippetStartupFetchingIntervalFallback[];
+// Intervals for trigger type 3: suggestions shown to the user.
+extern const char kSnippetShownFetchingIntervalWifi[];
+extern const char kSnippetShownFetchingIntervalFallback[];
// The pref name for today's count of RemoteSuggestionsFetcher requests, so far.
extern const char kSnippetFetcherRequestCount[];
diff --git a/chromium/components/ntp_snippets/reading_list/reading_list_distillation_state_util.cc b/chromium/components/ntp_snippets/reading_list/reading_list_distillation_state_util.cc
deleted file mode 100644
index e7361ad1300..00000000000
--- a/chromium/components/ntp_snippets/reading_list/reading_list_distillation_state_util.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2017 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 "components/ntp_snippets/reading_list/reading_list_distillation_state_util.h"
-
-#include "base/logging.h"
-
-namespace ntp_snippets {
-
-ReadingListEntry::DistillationState ReadingListStateFromSuggestionState(
- ReadingListSuggestionExtra::ReadingListSuggestionDistilledState
- distilled_state) {
- switch (distilled_state) {
- case ReadingListSuggestionExtra::ReadingListSuggestionDistilledState::
- PENDING:
- return ReadingListEntry::WAITING;
- case ReadingListSuggestionExtra::ReadingListSuggestionDistilledState::
- SUCCESS:
- return ReadingListEntry::PROCESSED;
- case ReadingListSuggestionExtra::ReadingListSuggestionDistilledState::
- FAILURE:
- return ReadingListEntry::DISTILLATION_ERROR;
- }
- NOTREACHED();
- return ReadingListEntry::PROCESSING;
-}
-
-ReadingListSuggestionExtra::ReadingListSuggestionDistilledState
-SuggestionStateFromReadingListState(
- ReadingListEntry::DistillationState distilled_state) {
- switch (distilled_state) {
- case ReadingListEntry::WILL_RETRY:
- case ReadingListEntry::PROCESSING:
- case ReadingListEntry::WAITING:
- return ReadingListSuggestionExtra::ReadingListSuggestionDistilledState::
- PENDING;
- case ReadingListEntry::PROCESSED:
- return ReadingListSuggestionExtra::ReadingListSuggestionDistilledState::
- SUCCESS;
- case ReadingListEntry::DISTILLATION_ERROR:
- return ReadingListSuggestionExtra::ReadingListSuggestionDistilledState::
- FAILURE;
- }
- NOTREACHED();
- return ReadingListSuggestionExtra::ReadingListSuggestionDistilledState::
- PENDING;
-}
-
-} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/reading_list/reading_list_distillation_state_util.h b/chromium/components/ntp_snippets/reading_list/reading_list_distillation_state_util.h
deleted file mode 100644
index a00553fc98a..00000000000
--- a/chromium/components/ntp_snippets/reading_list/reading_list_distillation_state_util.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2017 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 COMPONENTS_NTP_SNIPPETS_READING_LIST_READING_LIST_DISTILLATION_STATE_UTIL_H_
-#define COMPONENTS_NTP_SNIPPETS_READING_LIST_READING_LIST_DISTILLATION_STATE_UTIL_H_
-
-#include "components/ntp_snippets/content_suggestion.h"
-#include "components/reading_list/core/reading_list_entry.h"
-
-namespace ntp_snippets {
-
-ReadingListEntry::DistillationState ReadingListStateFromSuggestionState(
- ReadingListSuggestionExtra::ReadingListSuggestionDistilledState
- distilled_state);
-
-ReadingListSuggestionExtra::ReadingListSuggestionDistilledState
-SuggestionStateFromReadingListState(
- ReadingListEntry::DistillationState distilled_state);
-
-} // namespace ntp_snippets
-
-#endif // COMPONENTS_NTP_SNIPPETS_READING_LIST_READING_LIST_DISTILLATION_STATE_UTIL_H_
diff --git a/chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.cc b/chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.cc
index ed11ed83fda..9bf791c4857 100644
--- a/chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.cc
+++ b/chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.cc
@@ -11,8 +11,8 @@
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
#include "components/ntp_snippets/category.h"
-#include "components/ntp_snippets/reading_list/reading_list_distillation_state_util.h"
#include "components/reading_list/core/reading_list_entry.h"
#include "components/reading_list/core/reading_list_model.h"
#include "components/strings/grit/components_strings.h"
@@ -218,10 +218,16 @@ ContentSuggestion ReadingListSuggestionsProvider::ConvertEntry(
}
suggestion.set_publisher_name(
url_formatter::FormatUrl(entry->URL().GetOrigin()));
+ int64_t entry_time = entry->DistillationTime();
+ if (entry_time == 0) {
+ entry_time = entry->CreationTime();
+ }
+
+ suggestion.set_publish_date(
+ base::Time::FromDoubleT(entry_time / base::Time::kMicrosecondsPerSecond));
auto extra = base::MakeUnique<ReadingListSuggestionExtra>();
- extra->distilled_state =
- SuggestionStateFromReadingListState(entry->DistilledState());
+ extra->distilled = entry->DistilledState() == ReadingListEntry::PROCESSED;
extra->favicon_page_url =
entry->DistilledURL().is_valid() ? entry->DistilledURL() : entry->URL();
suggestion.set_reading_list_suggestion_extra(std::move(extra));
diff --git a/chromium/components/ntp_snippets/remote/fetch.py b/chromium/components/ntp_snippets/remote/fetch.py
index 48f448a3ec7..aa753f3e7e4 100755
--- a/chromium/components/ntp_snippets/remote/fetch.py
+++ b/chromium/components/ntp_snippets/remote/fetch.py
@@ -195,9 +195,9 @@ def Authenticate(args, headers, client_id, client_secret):
creds.apply(headers)
-def PrintShortResponse(r):
+def PrintShortResponse(j):
now = datetime.datetime.now()
- for category in r.json()["categories"]:
+ for category in j["categories"]:
print("%s: " % category["localizedTitle"])
for suggestion in category["suggestions"]:
attribution = suggestion["attribution"]
diff --git a/chromium/components/ntp_snippets/remote/json_request.cc b/chromium/components/ntp_snippets/remote/json_request.cc
index 3f7af6e8b2b..2ea9f4f7d57 100644
--- a/chromium/components/ntp_snippets/remote/json_request.cc
+++ b/chromium/components/ntp_snippets/remote/json_request.cc
@@ -52,8 +52,6 @@ namespace {
// Variation parameter for disabling the retry.
const char kBackground5xxRetriesName[] = "background_5xx_retries_count";
-const int kMaxExcludedIds = 100;
-
// Variation parameter for sending LanguageModel info to the server.
const char kSendTopLanguagesName[] = "send_top_languages";
@@ -321,9 +319,6 @@ std::string JsonRequest::Builder::BuildBody() const {
auto excluded = base::MakeUnique<base::ListValue>();
for (const auto& id : params_.excluded_ids) {
excluded->AppendString(id);
- if (excluded->GetSize() >= kMaxExcludedIds) {
- break;
- }
}
request->Set("excludedSuggestionIds", std::move(excluded));
diff --git a/chromium/components/ntp_snippets/remote/json_request_unittest.cc b/chromium/components/ntp_snippets/remote/json_request_unittest.cc
index d19f2c8b812..3791ccd5059 100644
--- a/chromium/components/ntp_snippets/remote/json_request_unittest.cc
+++ b/chromium/components/ntp_snippets/remote/json_request_unittest.cc
@@ -148,7 +148,7 @@ TEST_F(JsonRequestTest, BuildRequestUnauthenticated) {
"}"));
}
-TEST_F(JsonRequestTest, BuildRequestExcludedIds) {
+TEST_F(JsonRequestTest, ShouldNotTruncateExcludedIdsList) {
JsonRequest::Builder builder;
RequestParams params;
params.interactive_request = false;
@@ -180,9 +180,27 @@ TEST_F(JsonRequestTest, BuildRequestExcludedIds) {
" \"080\", \"081\", \"082\", \"083\", \"084\","
" \"085\", \"086\", \"087\", \"088\", \"089\","
" \"090\", \"091\", \"092\", \"093\", \"094\","
- " \"095\", \"096\", \"097\", \"098\", \"099\""
- // Truncated to 100 entries. Currently, they happen to
- // be those lexically first.
+ " \"095\", \"096\", \"097\", \"098\", \"099\","
+ " \"100\", \"101\", \"102\", \"103\", \"104\","
+ " \"105\", \"106\", \"107\", \"108\", \"109\","
+ " \"110\", \"111\", \"112\", \"113\", \"114\","
+ " \"115\", \"116\", \"117\", \"118\", \"119\","
+ " \"120\", \"121\", \"122\", \"123\", \"124\","
+ " \"125\", \"126\", \"127\", \"128\", \"129\","
+ " \"130\", \"131\", \"132\", \"133\", \"134\","
+ " \"135\", \"136\", \"137\", \"138\", \"139\","
+ " \"140\", \"141\", \"142\", \"143\", \"144\","
+ " \"145\", \"146\", \"147\", \"148\", \"149\","
+ " \"150\", \"151\", \"152\", \"153\", \"154\","
+ " \"155\", \"156\", \"157\", \"158\", \"159\","
+ " \"160\", \"161\", \"162\", \"163\", \"164\","
+ " \"165\", \"166\", \"167\", \"168\", \"169\","
+ " \"170\", \"171\", \"172\", \"173\", \"174\","
+ " \"175\", \"176\", \"177\", \"178\", \"179\","
+ " \"180\", \"181\", \"182\", \"183\", \"184\","
+ " \"185\", \"186\", \"187\", \"188\", \"189\","
+ " \"190\", \"191\", \"192\", \"193\", \"194\","
+ " \"195\", \"196\", \"197\", \"198\", \"199\""
" ],"
" \"userActivenessClass\": \"ACTIVE_NTP_USER\""
"}"));
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher_unittest.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher_unittest.cc
index 7607efe00ca..e5ffb4d0821 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher_unittest.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher_unittest.cc
@@ -30,6 +30,7 @@
#include "components/variations/entropy_provider.h"
#include "components/variations/variations_params_manager.h"
#include "google_apis/gaia/fake_oauth2_token_service_delegate.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -182,14 +183,16 @@ class DelegateCallingTestURLFetcherFactory
int id,
const GURL& url,
net::URLFetcher::RequestType request_type,
- net::URLFetcherDelegate* d) override {
+ net::URLFetcherDelegate* d,
+ net::NetworkTrafficAnnotationTag traffic_annotation) override {
if (GetFetcherByID(id)) {
LOG(WARNING) << "The ID " << id << " was already assigned to a fetcher."
<< "Its delegate will thereforde be called right now.";
DropAndCallDelegate(id);
}
fetchers_.push_back(id);
- return TestURLFetcherFactory::CreateURLFetcher(id, url, request_type, d);
+ return TestURLFetcherFactory::CreateURLFetcher(id, url, request_type, d,
+ traffic_annotation);
}
// Returns the raw pointer of the last created URL fetcher.
@@ -235,7 +238,8 @@ class FailingFakeURLFetcherFactory : public net::URLFetcherFactory {
int id,
const GURL& url,
net::URLFetcher::RequestType request_type,
- net::URLFetcherDelegate* d) override {
+ net::URLFetcherDelegate* d,
+ net::NetworkTrafficAnnotationTag traffic_annotation) override {
return base::MakeUnique<net::FakeURLFetcher>(
url, d, /*response_data=*/std::string(), net::HTTP_NOT_FOUND,
net::URLRequestStatus::FAILED);
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
index 2c637e3a57a..a3a8b9f6873 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
@@ -33,6 +33,7 @@
#include "components/prefs/pref_service.h"
#include "components/strings/grit/components_strings.h"
#include "components/variations/variations_associated_data.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image.h"
@@ -47,6 +48,10 @@ const int kMaxSuggestionCount = 10;
// Number of archived suggestions we keep around in memory.
const int kMaxArchivedSuggestionCount = 200;
+// Maximal number of dismissed suggestions to exclude when fetching new
+// suggestions from the server. This limit exists to decrease data usage.
+const int kMaxExcludedDismissedIds = 100;
+
// Keys for storing CategoryContent info in prefs.
const char kCategoryContentId[] = "id";
const char kCategoryContentTitle[] = "title";
@@ -192,6 +197,17 @@ void CallWithEmptyResults(const FetchDoneCallback& callback,
callback.Run(status, std::vector<ContentSuggestion>());
}
+void AddDismissedIdsToRequest(const RemoteSuggestion::PtrVector& dismissed,
+ RequestParams* request_params) {
+ // The latest ids are added first, because they are more relevant.
+ for (auto it = dismissed.rbegin(); it != dismissed.rend(); ++it) {
+ if (request_params->excluded_ids.size() == kMaxExcludedDismissedIds) {
+ break;
+ }
+ request_params->excluded_ids.insert((*it)->id());
+ }
+}
+
} // namespace
CachedImageFetcher::CachedImageFetcher(
@@ -288,10 +304,34 @@ void CachedImageFetcher::FetchImageFromNetwork(
return;
}
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation("remote_suggestions_provider", R"(
+ semantics {
+ sender: "Content Suggestion Thumbnail Fetch"
+ description:
+ "Retrieves thumbnails for content suggestions, for display on the "
+ "New Tab page or Chrome Home."
+ trigger:
+ "Triggered when the user looks at a content suggestion (and its "
+ "thumbnail isn't cached yet)."
+ data: "None."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: false
+ setting: "Currently not available, but in progress: crbug.com/703684"
+ chrome_policy {
+ NTPContentSuggestionsEnabled {
+ policy_options {mode: MANDATORY}
+ NTPContentSuggestionsEnabled: false
+ }
+ }
+ })");
image_fetcher_->StartOrQueueNetworkRequest(
suggestion_id.id_within_category(), url,
base::Bind(&CachedImageFetcher::OnImageDecodingDone,
- base::Unretained(this), callback));
+ base::Unretained(this), callback),
+ traffic_annotation);
}
RemoteSuggestionsProviderImpl::RemoteSuggestionsProviderImpl(
@@ -408,7 +448,7 @@ void RemoteSuggestionsProviderImpl::FetchSuggestions(
MarkEmptyCategoriesAsLoading();
- RequestParams params = BuildFetchParams();
+ RequestParams params = BuildFetchParams(/*fetched_category=*/base::nullopt);
params.interactive_request = interactive_request;
suggestions_fetcher_->FetchSnippets(
params,
@@ -441,7 +481,7 @@ void RemoteSuggestionsProviderImpl::Fetch(
},
base::Unretained(remote_suggestions_scheduler_), callback);
- RequestParams params = BuildFetchParams();
+ RequestParams params = BuildFetchParams(category);
params.excluded_ids.insert(known_suggestion_ids.begin(),
known_suggestion_ids.end());
params.interactive_request = true;
@@ -454,15 +494,23 @@ void RemoteSuggestionsProviderImpl::Fetch(
}
// Builds default fetcher params.
-RequestParams RemoteSuggestionsProviderImpl::BuildFetchParams() const {
+RequestParams RemoteSuggestionsProviderImpl::BuildFetchParams(
+ base::Optional<Category> fetched_category) const {
RequestParams result;
result.language_code = application_language_code_;
result.count_to_fetch = kMaxSuggestionCount;
+ // If this is a fetch for a specific category, its dismissed suggestions are
+ // added first to truncate them less.
+ if (fetched_category.has_value()) {
+ DCHECK(category_contents_.count(*fetched_category));
+ AddDismissedIdsToRequest(
+ category_contents_.find(*fetched_category)->second.dismissed, &result);
+ }
for (const auto& map_entry : category_contents_) {
- const CategoryContent& content = map_entry.second;
- for (const auto& dismissed_suggestion : content.dismissed) {
- result.excluded_ids.insert(dismissed_suggestion->id());
+ if (fetched_category.has_value() && map_entry.first == *fetched_category) {
+ continue;
}
+ AddDismissedIdsToRequest(map_entry.second.dismissed, &result);
}
return result;
}
@@ -684,31 +732,12 @@ void RemoteSuggestionsProviderImpl::OnFetchMoreFinished(
UpdateCategoryInfo(category, fetched_category.info);
SanitizeReceivedSuggestions(existing_content->dismissed,
&fetched_category.suggestions);
- // We compute the result now before modifying |fetched_category.suggestions|.
- // However, we wait with notifying the caller until the end of the method when
- // all state is updated.
std::vector<ContentSuggestion> result =
ConvertToContentSuggestions(category, fetched_category.suggestions);
-
- // Fill up the newly fetched suggestions with existing ones, store them, and
- // notify observers about new data.
- while (fetched_category.suggestions.size() <
- static_cast<size_t>(kMaxSuggestionCount) &&
- !existing_content->suggestions.empty()) {
- fetched_category.suggestions.emplace(
- fetched_category.suggestions.begin(),
- std::move(existing_content->suggestions.back()));
- existing_content->suggestions.pop_back();
- }
- std::vector<std::string> to_dismiss =
- *GetSuggestionIDVector(existing_content->suggestions);
- for (const auto& id : to_dismiss) {
- DismissSuggestionFromCategoryContent(existing_content, id);
- }
- DCHECK(existing_content->suggestions.empty());
-
- IntegrateSuggestions(existing_content,
- std::move(fetched_category.suggestions));
+ // Store the additional suggestions into the archive to be able to fetch
+ // images and favicons for them. Note that ArchiveSuggestions clears
+ // |fetched_category.suggestions|.
+ ArchiveSuggestions(existing_content, &fetched_category.suggestions);
// TODO(tschumann): We should properly honor the existing category state,
// e.g. to make sure we don't serve results after the sign-out. Revisit this:
@@ -716,7 +745,6 @@ void RemoteSuggestionsProviderImpl::OnFetchMoreFinished(
// status?
UpdateCategoryStatus(category, CategoryStatus::AVAILABLE);
fetching_callback.Run(Status::Success(), std::move(result));
- NotifyNewSuggestions(category, *existing_content);
}
void RemoteSuggestionsProviderImpl::OnFetchFinished(
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.h b/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.h
index 2540c3abae3..d84d00d4548 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.h
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.h
@@ -17,6 +17,7 @@
#include "base/callback_forward.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
+#include "base/optional.h"
#include "base/time/clock.h"
#include "base/time/time.h"
#include "components/image_fetcher/core/image_fetcher_delegate.h"
@@ -409,7 +410,9 @@ class RemoteSuggestionsProviderImpl final : public RemoteSuggestionsProvider {
void RestoreCategoriesFromPrefs();
void StoreCategoriesToPrefs();
- RequestParams BuildFetchParams() const;
+ // Absence of fetched category corresponds to fetching all categories.
+ RequestParams BuildFetchParams(
+ base::Optional<Category> fetched_category) const;
void MarkEmptyCategoriesAsLoading();
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc
index ee6175526de..0759b4f1cb6 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc
@@ -16,6 +16,7 @@
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@@ -48,6 +49,7 @@
#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
#include "components/signin/core/browser/fake_signin_manager.h"
#include "components/variations/variations_params_manager.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -336,7 +338,8 @@ class FailingFakeURLFetcherFactory : public net::URLFetcherFactory {
int id,
const GURL& url,
net::URLFetcher::RequestType request_type,
- net::URLFetcherDelegate* d) override {
+ net::URLFetcherDelegate* d,
+ net::NetworkTrafficAnnotationTag traffic_annotation) override {
return base::MakeUnique<net::FakeURLFetcher>(
url, d, /*response_data=*/std::string(), net::HTTP_NOT_FOUND,
net::URLRequestStatus::FAILED);
@@ -350,10 +353,11 @@ class MockImageFetcher : public ImageFetcher {
MOCK_METHOD1(SetImageDownloadLimit,
void(base::Optional<int64_t> max_download_bytes));
MOCK_METHOD1(SetDesiredImageFrameSize, void(const gfx::Size&));
- MOCK_METHOD3(StartOrQueueNetworkRequest,
+ MOCK_METHOD4(StartOrQueueNetworkRequest,
void(const std::string&,
const GURL&,
- const ImageFetcherCallback&));
+ const ImageFetcherCallback&,
+ const net::NetworkTrafficAnnotationTag&));
MOCK_METHOD0(GetImageDecoder, image_fetcher::ImageDecoder*());
};
@@ -1001,7 +1005,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, LoadsAdditionalSuggestions) {
// Verify we can resolve the image of the new suggestions.
ServeImageCallback cb =
base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting());
- EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _))
+ EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _, _))
.Times(2)
.WillRepeatedly(WithArgs<0, 2>(Invoke(CreateFunctor(cb))));
image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1));
@@ -1012,12 +1016,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, LoadsAdditionalSuggestions) {
image = FetchImage(service.get(), MakeArticleID("http://second"));
EXPECT_FALSE(image.IsEmpty());
EXPECT_EQ(1, image.Width());
-
- // Verify that the observer received the update as well. We should see the
- // newly-fetched items filled up with existing ones.
- EXPECT_THAT(observer().SuggestionsForCategory(articles_category()),
- ElementsAre(IdWithinCategoryEq("http://first"),
- IdWithinCategoryEq("http://second")));
}
// The tests TestMergingFetchedMoreSuggestionsFillup and
@@ -1025,14 +1023,14 @@ TEST_F(RemoteSuggestionsProviderImplTest, LoadsAdditionalSuggestions) {
// story:
// 1) fetch suggestions in NTP A
// 2) fetch more suggestions in NTP A.
-// 3) open new NTP B: See the last 10 results visible in step 2).
-// 4) fetch more suggestions in NTP B. Make sure no results from step 1) which
-// were superseded in step 2) get merged back in again.
+// 3) open new NTP B: See the first 10 results from step 1).
+// 4) fetch more suggestions in NTP B. Make sure the results are independent
+// from step 2)
// TODO(tschumann): Test step 4) on a higher level instead of peeking into the
// internal 'dismissed' data. The proper check is to make sure we tell the
// backend to exclude these suggestions.
TEST_F(RemoteSuggestionsProviderImplTest,
- TestMergingFetchedMoreSuggestionsFillup) {
+ FewMoreFetchedSuggestionsShouldNotInterfere) {
auto service = MakeSuggestionsProvider(/*set_empty_response=*/false);
LoadFromJSONString(service.get(),
GetTestJson({GetSuggestionWithUrl("http://id-1"),
@@ -1071,65 +1069,37 @@ TEST_F(RemoteSuggestionsProviderImplTest,
"http://id-9", "http://id-10"},
expect_receiving_two_new_suggestions);
- // Verify that the observer received the update as well. We should see the
- // newly-fetched items filled up with existing ones. The merging is done
- // mimicking a scrolling behavior.
+ // Verify that the observer still has the old set.
EXPECT_THAT(
observer().SuggestionsForCategory(articles_category()),
ElementsAre(
+ IdWithinCategoryEq("http://id-1"), IdWithinCategoryEq("http://id-2"),
IdWithinCategoryEq("http://id-3"), IdWithinCategoryEq("http://id-4"),
IdWithinCategoryEq("http://id-5"), IdWithinCategoryEq("http://id-6"),
IdWithinCategoryEq("http://id-7"), IdWithinCategoryEq("http://id-8"),
- IdWithinCategoryEq("http://id-9"), IdWithinCategoryEq("http://id-10"),
- IdWithinCategoryEq("http://more-id-1"),
- IdWithinCategoryEq("http://more-id-2")));
- // Verify the superseded suggestions got marked as dismissed.
- EXPECT_THAT(service->GetDismissedSuggestionsForTesting(articles_category()),
- ElementsAre(IdEq("http://id-1"), IdEq("http://id-2")));
-}
-
-TEST_F(RemoteSuggestionsProviderImplTest,
- ClearHistoryShouldDeleteArchivedSuggestions) {
- auto service = MakeSuggestionsProvider(/*set_empty_response=*/false);
- // First get suggestions into the archived state which happens through
- // subsequent fetches. Then we verify the entries are gone from the 'archived'
- // state by trying to load their images (and we shouldn't even know the URLs
- // anymore).
- LoadFromJSONString(service.get(),
- GetTestJson({GetSuggestionWithUrl("http://id-1"),
- GetSuggestionWithUrl("http://id-2")}));
- LoadFromJSONString(service.get(),
- GetTestJson({GetSuggestionWithUrl("http://new-id-1"),
- GetSuggestionWithUrl("http://new-id-2")}));
- // Make sure images of both batches are available. This is to sanity check our
- // assumptions for the test are right.
- ServeImageCallback cb =
- base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting());
- EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _))
- .Times(2)
- .WillRepeatedly(WithArgs<0, 2>(Invoke(CreateFunctor(cb))));
- image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1));
- gfx::Image image = FetchImage(service.get(), MakeArticleID("http://id-1"));
- ASSERT_FALSE(image.IsEmpty());
- ASSERT_EQ(1, image.Width());
- image = FetchImage(service.get(), MakeArticleID("http://new-id-1"));
- ASSERT_FALSE(image.IsEmpty());
- ASSERT_EQ(1, image.Width());
-
- service->ClearHistory(base::Time::UnixEpoch(), base::Time::Max(),
- base::Callback<bool(const GURL& url)>());
+ IdWithinCategoryEq("http://id-9"),
+ IdWithinCategoryEq("http://id-10")));
- // Make sure images of both batches are gone.
- // Verify we cannot resolve the image of the new suggestions.
- image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1));
- EXPECT_TRUE(
- FetchImage(service.get(), MakeArticleID("http://id-1")).IsEmpty());
- EXPECT_TRUE(
- FetchImage(service.get(), MakeArticleID("http://new-id-1")).IsEmpty());
+ // No interference from previous Fetch more: we can receive two other ones.
+ expect_receiving_two_new_suggestions =
+ base::Bind([](Status status, std::vector<ContentSuggestion> suggestions) {
+ ASSERT_THAT(suggestions, SizeIs(2));
+ EXPECT_THAT(suggestions[0], IdWithinCategoryEq("http://more-id-3"));
+ EXPECT_THAT(suggestions[1], IdWithinCategoryEq("http://more-id-4"));
+ });
+ LoadMoreFromJSONString(
+ service.get(), articles_category(),
+ GetTestJson({GetSuggestionWithUrl("http://more-id-3"),
+ GetSuggestionWithUrl("http://more-id-4")}),
+ /*known_ids=*/
+ {"http://id-1", "http://id-2", "http://id-3", "http://id-4",
+ "http://id-5", "http://id-6", "http://id-7", "http://id-8",
+ "http://id-9", "http://id-10"},
+ expect_receiving_two_new_suggestions);
}
TEST_F(RemoteSuggestionsProviderImplTest,
- TestMergingFetchedMoreSuggestionsReplaceAll) {
+ TenMoreFetchedSuggestionsShouldNotInterfere) {
auto service = MakeSuggestionsProvider(/*set_empty_response=*/false);
LoadFromJSONString(service.get(),
GetTestJson({GetSuggestionWithUrl("http://id-1"),
@@ -1183,24 +1153,88 @@ TEST_F(RemoteSuggestionsProviderImplTest,
"http://id-5", "http://id-6", "http://id-7", "http://id-8",
"http://id-9", "http://id-10"},
expect_receiving_ten_new_suggestions);
- EXPECT_THAT(observer().SuggestionsForCategory(articles_category()),
- ElementsAre(IdWithinCategoryEq("http://more-id-1"),
- IdWithinCategoryEq("http://more-id-2"),
- IdWithinCategoryEq("http://more-id-3"),
- IdWithinCategoryEq("http://more-id-4"),
- IdWithinCategoryEq("http://more-id-5"),
- IdWithinCategoryEq("http://more-id-6"),
- IdWithinCategoryEq("http://more-id-7"),
- IdWithinCategoryEq("http://more-id-8"),
- IdWithinCategoryEq("http://more-id-9"),
- IdWithinCategoryEq("http://more-id-10")));
- // Verify the superseded suggestions got marked as dismissed.
EXPECT_THAT(
- service->GetDismissedSuggestionsForTesting(articles_category()),
- ElementsAre(IdEq("http://id-1"), IdEq("http://id-2"), IdEq("http://id-3"),
- IdEq("http://id-4"), IdEq("http://id-5"), IdEq("http://id-6"),
- IdEq("http://id-7"), IdEq("http://id-8"), IdEq("http://id-9"),
- IdEq("http://id-10")));
+ observer().SuggestionsForCategory(articles_category()),
+ ElementsAre(
+ IdWithinCategoryEq("http://id-1"), IdWithinCategoryEq("http://id-2"),
+ IdWithinCategoryEq("http://id-3"), IdWithinCategoryEq("http://id-4"),
+ IdWithinCategoryEq("http://id-5"), IdWithinCategoryEq("http://id-6"),
+ IdWithinCategoryEq("http://id-7"), IdWithinCategoryEq("http://id-8"),
+ IdWithinCategoryEq("http://id-9"),
+ IdWithinCategoryEq("http://id-10")));
+
+ // This time, test receiving the same set.
+ expect_receiving_ten_new_suggestions =
+ base::Bind([](Status status, std::vector<ContentSuggestion> suggestions) {
+ EXPECT_THAT(suggestions,
+ ElementsAre(IdWithinCategoryEq("http://more-id-1"),
+ IdWithinCategoryEq("http://more-id-2"),
+ IdWithinCategoryEq("http://more-id-3"),
+ IdWithinCategoryEq("http://more-id-4"),
+ IdWithinCategoryEq("http://more-id-5"),
+ IdWithinCategoryEq("http://more-id-6"),
+ IdWithinCategoryEq("http://more-id-7"),
+ IdWithinCategoryEq("http://more-id-8"),
+ IdWithinCategoryEq("http://more-id-9"),
+ IdWithinCategoryEq("http://more-id-10")));
+ });
+ LoadMoreFromJSONString(
+ service.get(), articles_category(),
+ GetTestJson({GetSuggestionWithUrl("http://more-id-1"),
+ GetSuggestionWithUrl("http://more-id-2"),
+ GetSuggestionWithUrl("http://more-id-3"),
+ GetSuggestionWithUrl("http://more-id-4"),
+ GetSuggestionWithUrl("http://more-id-5"),
+ GetSuggestionWithUrl("http://more-id-6"),
+ GetSuggestionWithUrl("http://more-id-7"),
+ GetSuggestionWithUrl("http://more-id-8"),
+ GetSuggestionWithUrl("http://more-id-9"),
+ GetSuggestionWithUrl("http://more-id-10")}),
+ /*known_ids=*/
+ {"http://id-1", "http://id-2", "http://id-3", "http://id-4",
+ "http://id-5", "http://id-6", "http://id-7", "http://id-8",
+ "http://id-9", "http://id-10"},
+ expect_receiving_ten_new_suggestions);
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
+ ClearHistoryShouldDeleteArchivedSuggestions) {
+ auto service = MakeSuggestionsProvider(/*set_empty_response=*/false);
+ // First get suggestions into the archived state which happens through
+ // subsequent fetches. Then we verify the entries are gone from the 'archived'
+ // state by trying to load their images (and we shouldn't even know the URLs
+ // anymore).
+ LoadFromJSONString(service.get(),
+ GetTestJson({GetSuggestionWithUrl("http://id-1"),
+ GetSuggestionWithUrl("http://id-2")}));
+ LoadFromJSONString(service.get(),
+ GetTestJson({GetSuggestionWithUrl("http://new-id-1"),
+ GetSuggestionWithUrl("http://new-id-2")}));
+ // Make sure images of both batches are available. This is to sanity check our
+ // assumptions for the test are right.
+ ServeImageCallback cb =
+ base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting());
+ EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _, _))
+ .Times(2)
+ .WillRepeatedly(WithArgs<0, 2>(Invoke(CreateFunctor(cb))));
+ image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1));
+ gfx::Image image = FetchImage(service.get(), MakeArticleID("http://id-1"));
+ ASSERT_FALSE(image.IsEmpty());
+ ASSERT_EQ(1, image.Width());
+ image = FetchImage(service.get(), MakeArticleID("http://new-id-1"));
+ ASSERT_FALSE(image.IsEmpty());
+ ASSERT_EQ(1, image.Width());
+
+ service->ClearHistory(base::Time::UnixEpoch(), base::Time::Max(),
+ base::Callback<bool(const GURL& url)>());
+
+ // Make sure images of both batches are gone.
+ // Verify we cannot resolve the image of the new suggestions.
+ image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1));
+ EXPECT_TRUE(
+ FetchImage(service.get(), MakeArticleID("http://id-1")).IsEmpty());
+ EXPECT_TRUE(
+ FetchImage(service.get(), MakeArticleID("http://new-id-1")).IsEmpty());
}
// TODO(tschumann): We don't have test making sure the RemoteSuggestionsFetcher
@@ -1345,7 +1379,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, Dismiss) {
// Load the image to store it in the database.
ServeImageCallback cb =
base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting());
- EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _))
+ EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _, _))
.WillOnce(WithArgs<0, 2>(Invoke(CreateFunctor(cb))));
image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1));
gfx::Image image = FetchImage(service.get(), MakeArticleID(kSuggestionUrl));
@@ -1450,7 +1484,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, RemoveExpiredDismissedContent) {
// fetching expectations.
ServeImageCallback cb =
base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting());
- EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _))
+ EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _, _))
.WillOnce(WithArgs<0, 2>(Invoke(CreateFunctor(cb))));
image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1));
gfx::Image image = FetchImage(service.get(), MakeArticleID(kSuggestionUrl));
@@ -1624,7 +1658,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, ImageReturnedWithTheSameId) {
base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting());
{
InSequence s;
- EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _))
+ EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _, _))
.WillOnce(WithArgs<0, 2>(Invoke(CreateFunctor(cb))));
EXPECT_CALL(image_fetched, Call(_)).WillOnce(SaveArg<0>(&image));
}
@@ -1731,7 +1765,7 @@ TEST_F(RemoteSuggestionsProviderImplTest, ShouldClearOrphanedImagesOnRestart) {
ServeImageCallback cb =
base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting());
- EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _))
+ EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _, _))
.WillOnce(WithArgs<0, 2>(Invoke(CreateFunctor(cb))));
image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1));
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.cc
index 4b5a0e10b42..193628a55e4 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.cc
@@ -31,23 +31,27 @@ namespace {
// The FetchingInterval enum specifies overlapping time intervals that are used
// for scheduling the next remote suggestion fetch. Therefore a timer is created
// for each interval. Initially all the timers are started at the same time.
-// Fetches are only performed when conditions associated with the intervals are
-// met:
-// - A "soft" fetch is performed only at a moment when the user actively uses
-// Chrome after the interval has elapsed and causes a trigger that is currently
-// enabled while
-// - a "persistent" fetch is initiated automatically by the OS after the
-// interval elapses.
-// - A "wifi" fetch is performed only when the user is on a connection that
-// the OS classifies as unmetered while
-// - a "fallback" fetch happens on any connection.
+// A fetch for a given interval is only performed at the moment (after the
+// interval has elapsed) when the combination of two conditions associated with
+// the interval is met.
+// 1. Trigger contidion:
+// - STARTUP_*: the user starts / switches to Chrome;
+// - SHOWN_*: the suggestions surface is shown to the user;
+// - PERSISTENT_*: the OS initiates the scheduled fetching task (which has
+// been scheduled according to this interval).
+// 2. Connectivity condition:
+// - *_WIFI: the user is on a connection that the OS classifies as unmetered;
+// - *_FALLBACK: holds for any functional internet connection.
+//
// If a fetch failed, then only the corresponding timer is reset. The other
// timers are not touched.
enum class FetchingInterval {
PERSISTENT_FALLBACK,
PERSISTENT_WIFI,
- SOFT_FALLBACK,
- SOFT_WIFI,
+ STARTUP_FALLBACK,
+ STARTUP_WIFI,
+ SHOWN_FALLBACK,
+ SHOWN_WIFI,
COUNT
};
@@ -57,28 +61,36 @@ enum class FetchingInterval {
// The values of each array specify a default time interval for the intervals
// defined by the enum FetchingInterval. The default time intervals defined in
// the arrays can be overridden using different variation parameters.
-const double kDefaultFetchingIntervalHoursRareNtpUser[] = {48.0, 24.0, 8.0,
- 4.0};
-const double kDefaultFetchingIntervalHoursActiveNtpUser[] = {24.0, 8.0, 6.0,
- 3.0};
+const double kDefaultFetchingIntervalHoursRareNtpUser[] = {192.0, 96.0, 48.0,
+ 24.0, 12.0, 8.0};
+const double kDefaultFetchingIntervalHoursActiveNtpUser[] = {96.0, 48.0, 48.0,
+ 24.0, 12.0, 8.0};
const double kDefaultFetchingIntervalHoursActiveSuggestionsConsumer[] = {
- 24.0, 6.0, 2.0, 1.0};
+ 48.0, 24.0, 24.0, 6.0, 2.0, 1.0};
// Variation parameters than can be used to override the default fetching
-// intervals.
+// intervals. For backwards compatibility, we do not rename
+// - the "fetching_" params (should be "persistent_fetching_");
+// - the "soft_" params (should be "shown_").
const char* kFetchingIntervalParamNameRareNtpUser[] = {
"fetching_interval_hours-fallback-rare_ntp_user",
"fetching_interval_hours-wifi-rare_ntp_user",
+ "startup_fetching_interval_hours-fallback-rare_ntp_user",
+ "startup_fetching_interval_hours-wifi-rare_ntp_user",
"soft_fetching_interval_hours-fallback-rare_ntp_user",
"soft_fetching_interval_hours-wifi-rare_ntp_user"};
const char* kFetchingIntervalParamNameActiveNtpUser[] = {
"fetching_interval_hours-fallback-active_ntp_user",
"fetching_interval_hours-wifi-active_ntp_user",
+ "startup_fetching_interval_hours-fallback-active_ntp_user",
+ "startup_fetching_interval_hours-wifi-active_ntp_user",
"soft_fetching_interval_hours-fallback-active_ntp_user",
"soft_fetching_interval_hours-wifi-active_ntp_user"};
const char* kFetchingIntervalParamNameActiveSuggestionsConsumer[] = {
"fetching_interval_hours-fallback-active_suggestions_consumer",
"fetching_interval_hours-wifi-active_suggestions_consumer",
+ "startup_fetching_interval_hours-fallback-active_suggestions_consumer",
+ "startup_fetching_interval_hours-wifi-active_suggestions_consumer",
"soft_fetching_interval_hours-fallback-active_suggestions_consumer",
"soft_fetching_interval_hours-wifi-active_suggestions_consumer"};
@@ -174,14 +186,14 @@ void ReportTimeUntilFirstSoftTrigger(UserClassifier::UserClass user_class,
}
}
-void ReportTimeUntilSoftFetch(UserClassifier::UserClass user_class,
- base::TimeDelta time_until_soft_fetch) {
+void ReportTimeUntilShownFetch(UserClassifier::UserClass user_class,
+ base::TimeDelta time_until_shown_fetch) {
switch (user_class) {
case UserClassifier::UserClass::RARE_NTP_USER:
UMA_HISTOGRAM_CUSTOM_TIMES(
"NewTabPage.ContentSuggestions.TimeUntilSoftFetch."
"RareNTPUser",
- time_until_soft_fetch, base::TimeDelta::FromSeconds(1),
+ time_until_shown_fetch, base::TimeDelta::FromSeconds(1),
base::TimeDelta::FromDays(7),
/*bucket_count=*/50);
break;
@@ -189,7 +201,7 @@ void ReportTimeUntilSoftFetch(UserClassifier::UserClass user_class,
UMA_HISTOGRAM_CUSTOM_TIMES(
"NewTabPage.ContentSuggestions.TimeUntilSoftFetch."
"ActiveNTPUser",
- time_until_soft_fetch, base::TimeDelta::FromSeconds(1),
+ time_until_shown_fetch, base::TimeDelta::FromSeconds(1),
base::TimeDelta::FromDays(7),
/*bucket_count=*/50);
break;
@@ -197,7 +209,37 @@ void ReportTimeUntilSoftFetch(UserClassifier::UserClass user_class,
UMA_HISTOGRAM_CUSTOM_TIMES(
"NewTabPage.ContentSuggestions.TimeUntilSoftFetch."
"ActiveSuggestionsConsumer",
- time_until_soft_fetch, base::TimeDelta::FromSeconds(1),
+ time_until_shown_fetch, base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromDays(7),
+ /*bucket_count=*/50);
+ break;
+ }
+}
+
+void ReportTimeUntilStartupFetch(UserClassifier::UserClass user_class,
+ base::TimeDelta time_until_startup_fetch) {
+ switch (user_class) {
+ case UserClassifier::UserClass::RARE_NTP_USER:
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "NewTabPage.ContentSuggestions.TimeUntilStartupFetch."
+ "RareNTPUser",
+ time_until_startup_fetch, base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromDays(7),
+ /*bucket_count=*/50);
+ break;
+ case UserClassifier::UserClass::ACTIVE_NTP_USER:
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "NewTabPage.ContentSuggestions.TimeUntilStartupFetch."
+ "ActiveNTPUser",
+ time_until_startup_fetch, base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromDays(7),
+ /*bucket_count=*/50);
+ break;
+ case UserClassifier::UserClass::ACTIVE_SUGGESTIONS_CONSUMER:
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "NewTabPage.ContentSuggestions.TimeUntilStartupFetch."
+ "ActiveSuggestionsConsumer",
+ time_until_startup_fetch, base::TimeDelta::FromSeconds(1),
base::TimeDelta::FromDays(7),
/*bucket_count=*/50);
break;
@@ -288,8 +330,10 @@ bool RemoteSuggestionsSchedulerImpl::FetchingSchedule::operator==(
const FetchingSchedule& other) const {
return interval_persistent_wifi == other.interval_persistent_wifi &&
interval_persistent_fallback == other.interval_persistent_fallback &&
- interval_soft_wifi == other.interval_soft_wifi &&
- interval_soft_fallback == other.interval_soft_fallback;
+ interval_startup_wifi == other.interval_startup_wifi &&
+ interval_startup_fallback == other.interval_startup_fallback &&
+ interval_shown_wifi == other.interval_shown_wifi &&
+ interval_shown_fallback == other.interval_shown_fallback;
}
bool RemoteSuggestionsSchedulerImpl::FetchingSchedule::operator!=(
@@ -300,7 +344,9 @@ bool RemoteSuggestionsSchedulerImpl::FetchingSchedule::operator!=(
bool RemoteSuggestionsSchedulerImpl::FetchingSchedule::is_empty() const {
return interval_persistent_wifi.is_zero() &&
interval_persistent_fallback.is_zero() &&
- interval_soft_wifi.is_zero() && interval_soft_fallback.is_zero();
+ interval_startup_wifi.is_zero() &&
+ interval_startup_fallback.is_zero() && interval_shown_wifi.is_zero() &&
+ interval_shown_fallback.is_zero();
}
// The TriggerType enum specifies values for the events that can trigger
@@ -361,8 +407,11 @@ void RemoteSuggestionsSchedulerImpl::RegisterProfilePrefs(
registry->RegisterInt64Pref(prefs::kSnippetPersistentFetchingIntervalWifi, 0);
registry->RegisterInt64Pref(prefs::kSnippetPersistentFetchingIntervalFallback,
0);
- registry->RegisterInt64Pref(prefs::kSnippetSoftFetchingIntervalWifi, 0);
- registry->RegisterInt64Pref(prefs::kSnippetSoftFetchingIntervalFallback, 0);
+ registry->RegisterInt64Pref(prefs::kSnippetStartupFetchingIntervalWifi, 0);
+ registry->RegisterInt64Pref(prefs::kSnippetStartupFetchingIntervalFallback,
+ 0);
+ registry->RegisterInt64Pref(prefs::kSnippetShownFetchingIntervalWifi, 0);
+ registry->RegisterInt64Pref(prefs::kSnippetShownFetchingIntervalFallback, 0);
registry->RegisterInt64Pref(prefs::kSnippetLastFetchAttempt, 0);
// Cleanup procedure in M59. Remove for M62.
@@ -488,10 +537,14 @@ RemoteSuggestionsSchedulerImpl::GetDesiredFetchingSchedule() const {
GetDesiredFetchingInterval(FetchingInterval::PERSISTENT_WIFI, user_class);
schedule.interval_persistent_fallback = GetDesiredFetchingInterval(
FetchingInterval::PERSISTENT_FALLBACK, user_class);
- schedule.interval_soft_wifi =
- GetDesiredFetchingInterval(FetchingInterval::SOFT_WIFI, user_class);
- schedule.interval_soft_fallback =
- GetDesiredFetchingInterval(FetchingInterval::SOFT_FALLBACK, user_class);
+ schedule.interval_startup_wifi =
+ GetDesiredFetchingInterval(FetchingInterval::STARTUP_WIFI, user_class);
+ schedule.interval_startup_fallback = GetDesiredFetchingInterval(
+ FetchingInterval::STARTUP_FALLBACK, user_class);
+ schedule.interval_shown_wifi =
+ GetDesiredFetchingInterval(FetchingInterval::SHOWN_WIFI, user_class);
+ schedule.interval_shown_fallback =
+ GetDesiredFetchingInterval(FetchingInterval::SHOWN_FALLBACK, user_class);
return schedule;
}
@@ -502,10 +555,14 @@ void RemoteSuggestionsSchedulerImpl::LoadLastFetchingSchedule() {
schedule_.interval_persistent_fallback =
base::TimeDelta::FromInternalValue(profile_prefs_->GetInt64(
prefs::kSnippetPersistentFetchingIntervalFallback));
- schedule_.interval_soft_wifi = base::TimeDelta::FromInternalValue(
- profile_prefs_->GetInt64(prefs::kSnippetSoftFetchingIntervalWifi));
- schedule_.interval_soft_fallback = base::TimeDelta::FromInternalValue(
- profile_prefs_->GetInt64(prefs::kSnippetSoftFetchingIntervalFallback));
+ schedule_.interval_startup_wifi = base::TimeDelta::FromInternalValue(
+ profile_prefs_->GetInt64(prefs::kSnippetStartupFetchingIntervalWifi));
+ schedule_.interval_startup_fallback = base::TimeDelta::FromInternalValue(
+ profile_prefs_->GetInt64(prefs::kSnippetStartupFetchingIntervalFallback));
+ schedule_.interval_shown_wifi = base::TimeDelta::FromInternalValue(
+ profile_prefs_->GetInt64(prefs::kSnippetShownFetchingIntervalWifi));
+ schedule_.interval_shown_fallback = base::TimeDelta::FromInternalValue(
+ profile_prefs_->GetInt64(prefs::kSnippetShownFetchingIntervalFallback));
}
void RemoteSuggestionsSchedulerImpl::StoreFetchingSchedule() {
@@ -515,10 +572,15 @@ void RemoteSuggestionsSchedulerImpl::StoreFetchingSchedule() {
profile_prefs_->SetInt64(
prefs::kSnippetPersistentFetchingIntervalFallback,
schedule_.interval_persistent_fallback.ToInternalValue());
- profile_prefs_->SetInt64(prefs::kSnippetSoftFetchingIntervalWifi,
- schedule_.interval_soft_wifi.ToInternalValue());
- profile_prefs_->SetInt64(prefs::kSnippetSoftFetchingIntervalFallback,
- schedule_.interval_soft_fallback.ToInternalValue());
+ profile_prefs_->SetInt64(prefs::kSnippetStartupFetchingIntervalWifi,
+ schedule_.interval_startup_wifi.ToInternalValue());
+ profile_prefs_->SetInt64(
+ prefs::kSnippetStartupFetchingIntervalFallback,
+ schedule_.interval_startup_fallback.ToInternalValue());
+ profile_prefs_->SetInt64(prefs::kSnippetShownFetchingIntervalWifi,
+ schedule_.interval_shown_wifi.ToInternalValue());
+ profile_prefs_->SetInt64(prefs::kSnippetShownFetchingIntervalFallback,
+ schedule_.interval_shown_fallback.ToInternalValue());
}
void RemoteSuggestionsSchedulerImpl::RefetchInTheBackgroundIfAppropriate(
@@ -541,7 +603,8 @@ void RemoteSuggestionsSchedulerImpl::RefetchInTheBackgroundIfAppropriate(
clock_->Now() - last_fetch_attempt_time);
}
- if (is_soft && !ShouldRefetchInTheBackgroundNow(last_fetch_attempt_time)) {
+ if (is_soft &&
+ !ShouldRefetchInTheBackgroundNow(last_fetch_attempt_time, trigger)) {
return;
}
@@ -549,12 +612,20 @@ void RemoteSuggestionsSchedulerImpl::RefetchInTheBackgroundIfAppropriate(
return;
}
- if (is_soft) {
- ReportTimeUntilSoftFetch(user_classifier_->GetUserClass(),
- clock_->Now() - last_fetch_attempt_time);
- } else {
- ReportTimeUntilPersistentFetch(user_classifier_->GetUserClass(),
- clock_->Now() - last_fetch_attempt_time);
+ base::TimeDelta diff = clock_->Now() - last_fetch_attempt_time;
+ switch (trigger) {
+ case TriggerType::PERSISTENT_SCHEDULER_WAKE_UP:
+ ReportTimeUntilPersistentFetch(user_classifier_->GetUserClass(), diff);
+ break;
+ case TriggerType::NTP_OPENED:
+ ReportTimeUntilShownFetch(user_classifier_->GetUserClass(), diff);
+ break;
+ case TriggerType::BROWSER_FOREGROUNDED:
+ case TriggerType::BROWSER_COLD_START:
+ ReportTimeUntilStartupFetch(user_classifier_->GetUserClass(), diff);
+ break;
+ case TriggerType::COUNT:
+ NOTREACHED();
}
UMA_HISTOGRAM_ENUMERATION(
@@ -568,16 +639,23 @@ void RemoteSuggestionsSchedulerImpl::RefetchInTheBackgroundIfAppropriate(
}
bool RemoteSuggestionsSchedulerImpl::ShouldRefetchInTheBackgroundNow(
- base::Time last_fetch_attempt_time) {
+ base::Time last_fetch_attempt_time,
+ TriggerType trigger) {
// If we have no persistent scheduler to ask, err on the side of caution.
bool wifi = false;
if (persistent_scheduler_) {
wifi = persistent_scheduler_->IsOnUnmeteredConnection();
}
- base::Time first_allowed_fetch_time =
- last_fetch_attempt_time +
- (wifi ? schedule_.interval_soft_wifi : schedule_.interval_soft_fallback);
+ base::Time first_allowed_fetch_time = last_fetch_attempt_time;
+ if (trigger == TriggerType::NTP_OPENED) {
+ first_allowed_fetch_time += (wifi ? schedule_.interval_shown_wifi
+ : schedule_.interval_shown_fallback);
+ } else {
+ first_allowed_fetch_time += (wifi ? schedule_.interval_startup_wifi
+ : schedule_.interval_startup_fallback);
+ }
+
base::Time now = clock_->Now();
return background_fetches_allowed_after_ <= now &&
first_allowed_fetch_time <= now;
@@ -686,7 +764,8 @@ RemoteSuggestionsSchedulerImpl::GetEnabledTriggerTypes() {
std::set<RemoteSuggestionsSchedulerImpl::TriggerType>
RemoteSuggestionsSchedulerImpl::GetDefaultEnabledTriggerTypes() {
- return {TriggerType::PERSISTENT_SCHEDULER_WAKE_UP, TriggerType::NTP_OPENED};
+ return {TriggerType::PERSISTENT_SCHEDULER_WAKE_UP, TriggerType::NTP_OPENED,
+ TriggerType::BROWSER_COLD_START, TriggerType::BROWSER_FOREGROUNDED};
}
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.h b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.h
index 9921f51489a..3e103624bec 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.h
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.h
@@ -71,8 +71,10 @@ class RemoteSuggestionsSchedulerImpl : public RemoteSuggestionsScheduler {
base::TimeDelta interval_persistent_wifi;
base::TimeDelta interval_persistent_fallback;
- base::TimeDelta interval_soft_wifi;
- base::TimeDelta interval_soft_fallback;
+ base::TimeDelta interval_startup_wifi;
+ base::TimeDelta interval_startup_fallback;
+ base::TimeDelta interval_shown_wifi;
+ base::TimeDelta interval_shown_fallback;
};
enum class TriggerType;
@@ -91,9 +93,10 @@ class RemoteSuggestionsSchedulerImpl : public RemoteSuggestionsScheduler {
// timing is appropriate for another fetch.
void RefetchInTheBackgroundIfAppropriate(TriggerType trigger);
- // Checks whether it is time to perform a soft background fetch, according to
- // |schedule|.
- bool ShouldRefetchInTheBackgroundNow(base::Time last_fetch_attempt_time);
+ // Checks whether it is time to perform a soft background fetch for |trigger|,
+ // according to |schedule|.
+ bool ShouldRefetchInTheBackgroundNow(base::Time last_fetch_attempt_time,
+ TriggerType trigger);
// Returns whether background fetching (for the given |trigger|) is disabled.
bool BackgroundFetchesDisabled(TriggerType trigger) const;
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc
index ea142787bcd..0c22282ea0a 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc
@@ -489,8 +489,8 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
// Make the first soft fetch successful.
scheduler()->OnBrowserForegrounded();
signal_fetch_done.Run(Status::Success());
- // Open NTP again after 4hrs.
- test_clock()->Advance(base::TimeDelta::FromHours(4));
+ // Open NTP again after 9hrs.
+ test_clock()->Advance(base::TimeDelta::FromHours(24));
scheduler()->OnBrowserForegrounded();
}
@@ -603,7 +603,7 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
}
TEST_F(RemoteSuggestionsSchedulerImplTest,
- ReschedulesWhenSoftWifiParamChanges) {
+ ReschedulesWhenShownWifiParamChanges) {
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(2);
ActivateProvider();
@@ -617,7 +617,7 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
}
TEST_F(RemoteSuggestionsSchedulerImplTest,
- ReschedulesWhenSoftFallbackParamChanges) {
+ ReschedulesWhenShownFallbackParamChanges) {
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(2);
ActivateProvider();
@@ -630,12 +630,40 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
ActivateProvider();
}
-TEST_F(RemoteSuggestionsSchedulerImplTest, FetchIntervalForSoftTriggerOnWifi) {
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ReschedulesWhenStartupWifiParamChanges) {
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(2);
+ ActivateProvider();
+
+ // UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
+ // null. Change the on usage interval for this class.
+ SetVariationParameter("startup_fetching_interval_hours-wifi-active_ntp_user",
+ "1.5");
+
+ // Schedule() should get called for the second time after params have changed.
+ ActivateProvider();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest,
+ ReschedulesWhenStartupFallbackParamChanges) {
+ EXPECT_CALL(*persistent_scheduler(), Schedule(_, _)).Times(2);
+ ActivateProvider();
+
+ // UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
+ // null. Change the fallback interval for this class.
+ SetVariationParameter(
+ "startup_fetching_interval_hours-fallback-active_ntp_user", "1.5");
+
+ // Schedule() should get called for the second time after params have changed.
+ ActivateProvider();
+}
+
+TEST_F(RemoteSuggestionsSchedulerImplTest, FetchIntervalForShownTriggerOnWifi) {
// Pretend we are on WiFi (already done in ctor, we make it explicit here).
EXPECT_CALL(*persistent_scheduler(), IsOnUnmeteredConnection())
.WillRepeatedly(Return(true));
- // UserClassifier defaults to UserClass::ACTIVE_NTP_USER which uses a 3h time
- // interval by default for soft background fetches on WiFi.
+ // UserClassifier defaults to UserClass::ACTIVE_NTP_USER which uses a 8h time
+ // interval by default for shown trigger on WiFi.
// Initial scheduling after being enabled.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
@@ -651,22 +679,22 @@ TEST_F(RemoteSuggestionsSchedulerImplTest, FetchIntervalForSoftTriggerOnWifi) {
signal_fetch_done.Run(Status::Success());
// Open NTP again after too short delay. This time no fetch is executed.
- test_clock()->Advance(base::TimeDelta::FromMinutes(30));
+ test_clock()->Advance(base::TimeDelta::FromHours(1));
scheduler()->OnNTPOpened();
// Open NTP after another delay, now together long enough to issue a fetch.
- test_clock()->Advance(base::TimeDelta::FromMinutes(150));
+ test_clock()->Advance(base::TimeDelta::FromHours(7));
EXPECT_CALL(*provider(), RefetchInTheBackground(_));
scheduler()->OnNTPOpened();
}
TEST_F(RemoteSuggestionsSchedulerImplTest,
- OverrideFetchIntervalForSoftTriggerOnWifi) {
+ OverrideFetchIntervalForShownTriggerOnWifi) {
// Pretend we are on WiFi (already done in ctor, we make it explicit here).
EXPECT_CALL(*persistent_scheduler(), IsOnUnmeteredConnection())
.WillRepeatedly(Return(true));
// UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
- // null. Change the on usage interval for this class from 2h to 30min.
+ // null. Change the interval for this class from 4h to 30min.
SetVariationParameter("soft_fetching_interval_hours-wifi-active_ntp_user",
"0.5");
@@ -694,12 +722,12 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
}
TEST_F(RemoteSuggestionsSchedulerImplTest,
- FetchIntervalForSoftTriggerOnFallback) {
+ FetchIntervalForShownTriggerOnFallback) {
// Pretend we are not on wifi -> fallback connection.
EXPECT_CALL(*persistent_scheduler(), IsOnUnmeteredConnection())
.WillRepeatedly(Return(false));
- // UserClassifier defaults to UserClass::ACTIVE_NTP_USER which uses a 6h time
- // interval by default for soft background fetches not on WiFi.
+ // UserClassifier defaults to UserClass::ACTIVE_NTP_USER which uses a 12h time
+ // interval by default for shown trigger not on WiFi.
// Initial scheduling after being enabled.
EXPECT_CALL(*persistent_scheduler(), Schedule(_, _));
@@ -715,22 +743,22 @@ TEST_F(RemoteSuggestionsSchedulerImplTest,
signal_fetch_done.Run(Status::Success());
// Open NTP again after too short delay. This time no fetch is executed.
- test_clock()->Advance(base::TimeDelta::FromMinutes(300));
+ test_clock()->Advance(base::TimeDelta::FromHours(5));
scheduler()->OnNTPOpened();
// Open NTP after another delay, now together long enough to issue a fetch.
- test_clock()->Advance(base::TimeDelta::FromMinutes(60));
+ test_clock()->Advance(base::TimeDelta::FromHours(7));
EXPECT_CALL(*provider(), RefetchInTheBackground(_));
scheduler()->OnNTPOpened();
}
TEST_F(RemoteSuggestionsSchedulerImplTest,
- OverrideFetchIntervalForSoftTriggerOnFallback) {
+ OverrideFetchIntervalForShownTriggerOnFallback) {
// Pretend we are not on wifi -> fallback connection.
EXPECT_CALL(*persistent_scheduler(), IsOnUnmeteredConnection())
.WillRepeatedly(Return(false));
// UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
- // null. Change the on usage interval for this class from 4h to 30min.
+ // null. Change the interval for this class from 4h to 30min.
SetVariationParameter("soft_fetching_interval_hours-fallback-active_ntp_user",
"0.5");
diff --git a/chromium/components/ntp_snippets/user_classifier.cc b/chromium/components/ntp_snippets/user_classifier.cc
index 92b0312de49..a2461be9ef9 100644
--- a/chromium/components/ntp_snippets/user_classifier.cc
+++ b/chromium/components/ntp_snippets/user_classifier.cc
@@ -41,11 +41,13 @@ const double kMinHours = 0.5;
const char kMinHoursParam[] = "user_classifier_min_hours";
// Classification constants.
-const double kActiveConsumerClicksAtLeastOncePerHours = 72;
+const double kActiveConsumerClicksAtLeastOncePerHours = 96;
const char kActiveConsumerClicksAtLeastOncePerHoursParam[] =
"user_classifier_active_consumer_clicks_at_least_once_per_hours";
-const double kRareUserOpensNTPAtMostOncePerHours = 96;
+// The previous value in production was 72, i.e. 3 days. The new value is a
+// cautios shift in the direction we want (having slightly more rare users).
+const double kRareUserOpensNTPAtMostOncePerHours = 66;
const char kRareUserOpensNTPAtMostOncePerHoursParam[] =
"user_classifier_rare_user_opens_ntp_at_most_once_per_hours";
@@ -73,7 +75,7 @@ const char* kLastTimeKeys[] = {prefs::kUserClassifierLastTimeToOpenNTP,
prefs::kUserClassifierLastTimeToUseSuggestions};
// Default lengths of the intervals for new users for the metrics.
-const double kInitialHoursBetweenEvents[] = {24, 48, 96};
+const double kInitialHoursBetweenEvents[] = {24, 48, 120};
const char* kInitialHoursBetweenEventsParams[] = {
"user_classifier_default_interval_ntp_opened",
"user_classifier_default_interval_suggestions_shown",