summaryrefslogtreecommitdiff
path: root/chromium/components/ntp_tiles
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-11-20 10:33:36 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-11-22 11:45:12 +0000
commitbe59a35641616a4cf23c4a13fa0632624b021c1b (patch)
tree9da183258bdf9cc413f7562079d25ace6955467f /chromium/components/ntp_tiles
parentd702e4b6a64574e97fc7df8fe3238cde70242080 (diff)
downloadqtwebengine-chromium-be59a35641616a4cf23c4a13fa0632624b021c1b.tar.gz
BASELINE: Update Chromium to 62.0.3202.101
Change-Id: I2d5eca8117600df6d331f6166ab24d943d9814ac Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/components/ntp_tiles')
-rw-r--r--chromium/components/ntp_tiles/BUILD.gn2
-rw-r--r--chromium/components/ntp_tiles/constants.cc6
-rw-r--r--chromium/components/ntp_tiles/constants.h7
-rw-r--r--chromium/components/ntp_tiles/icon_cacher_impl.cc4
-rw-r--r--chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc29
-rw-r--r--chromium/components/ntp_tiles/metrics.cc5
-rw-r--r--chromium/components/ntp_tiles/metrics_unittest.cc31
-rw-r--r--chromium/components/ntp_tiles/most_visited_sites.cc168
-rw-r--r--chromium/components/ntp_tiles/most_visited_sites.h35
-rw-r--r--chromium/components/ntp_tiles/most_visited_sites_unittest.cc585
-rw-r--r--chromium/components/ntp_tiles/popular_sites.h7
-rw-r--r--chromium/components/ntp_tiles/popular_sites_impl.cc108
-rw-r--r--chromium/components/ntp_tiles/popular_sites_impl.h6
-rw-r--r--chromium/components/ntp_tiles/popular_sites_impl_unittest.cc254
-rw-r--r--chromium/components/ntp_tiles/pref_names.cc6
-rw-r--r--chromium/components/ntp_tiles/pref_names.h5
-rw-r--r--chromium/components/ntp_tiles/section_type.h30
-rw-r--r--chromium/components/ntp_tiles/tile_source.h2
-rw-r--r--chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc8
-rw-r--r--chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.h3
-rw-r--r--chromium/components/ntp_tiles/webui/resources/ntp_tiles_internals.html13
21 files changed, 996 insertions, 318 deletions
diff --git a/chromium/components/ntp_tiles/BUILD.gn b/chromium/components/ntp_tiles/BUILD.gn
index d9704187e88..300d4758576 100644
--- a/chromium/components/ntp_tiles/BUILD.gn
+++ b/chromium/components/ntp_tiles/BUILD.gn
@@ -28,6 +28,7 @@ static_library("ntp_tiles") {
"popular_sites_impl.h",
"pref_names.cc",
"pref_names.h",
+ "section_type.h",
"switches.cc",
"switches.h",
"tile_source.h",
@@ -111,6 +112,7 @@ source_set("unit_tests") {
if (is_android) {
java_cpp_enum("ntp_tiles_enums_java") {
sources = [
+ "section_type.h",
"tile_source.h",
"tile_visual_type.h",
]
diff --git a/chromium/components/ntp_tiles/constants.cc b/chromium/components/ntp_tiles/constants.cc
index 6af7a1727cd..048cf796baa 100644
--- a/chromium/components/ntp_tiles/constants.cc
+++ b/chromium/components/ntp_tiles/constants.cc
@@ -18,6 +18,12 @@ extern const base::Feature kPopularSitesBakedInContentFeature{
extern const base::Feature kNtpMostLikelyFaviconsFromServerFeature{
"NTPMostLikelyFaviconsFromServer", base::FEATURE_DISABLED_BY_DEFAULT};
+extern const base::Feature kLowerResolutionFaviconsFeature{
+ "NTPTilesLowerResolutionFavicons", base::FEATURE_DISABLED_BY_DEFAULT};
+
+extern const base::Feature kSiteExplorationUiFeature{
+ "SiteExplorationUi", base::FEATURE_DISABLED_BY_DEFAULT};
+
bool AreNtpMostLikelyFaviconsFromServerEnabled() {
// Check if the experimental flag is forced on or off.
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
diff --git a/chromium/components/ntp_tiles/constants.h b/chromium/components/ntp_tiles/constants.h
index 4af8d54413b..03a2be48a1e 100644
--- a/chromium/components/ntp_tiles/constants.h
+++ b/chromium/components/ntp_tiles/constants.h
@@ -23,6 +23,13 @@ extern const base::Feature kPopularSitesBakedInContentFeature;
// Likely tiles on the New Tab Page.
extern const base::Feature kNtpMostLikelyFaviconsFromServerFeature;
+// Feature to allow displaying lower resolution favicons for Tiles on the New
+// Tab Page.
+extern const base::Feature kLowerResolutionFaviconsFeature;
+
+// Feature to provide site exploration tiles in addition to personal tiles.
+extern const base::Feature kSiteExplorationUiFeature;
+
// Use this to find out whether the kNtpMostLikelyFaviconsFromServerFeature is
// enabled. This helper function abstracts iOS special way to override the
// feature (via command-line params).
diff --git a/chromium/components/ntp_tiles/icon_cacher_impl.cc b/chromium/components/ntp_tiles/icon_cacher_impl.cc
index 7b9e06ff2d4..c1518fd5e8c 100644
--- a/chromium/components/ntp_tiles/icon_cacher_impl.cc
+++ b/chromium/components/ntp_tiles/icon_cacher_impl.cc
@@ -133,7 +133,7 @@ void IconCacherImpl::OnGetFaviconImageForPageURLFinished(
destination: WEBSITE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting: "This feature cannot be disabled in settings."
policy_exception_justification: "Not implemented."
})");
@@ -252,7 +252,7 @@ void IconCacherImpl::OnGetLargeIconOrFallbackStyleFinished(
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting:
"Users can disable this feature via 'History' setting under "
"'Advanced sync settings'."
diff --git a/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc b/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc
index 2ce20e89b7d..94ffc498e72 100644
--- a/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc
+++ b/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc
@@ -437,9 +437,7 @@ TEST_F(IconCacherTestPopularSites, LargeNotCachedAndFetchPerformedOnlyOnce) {
class IconCacherTestMostLikely : public IconCacherTestBase {
protected:
IconCacherTestMostLikely()
- : large_icon_service_background_task_runner_(
- new base::TestSimpleTaskRunner()),
- fetcher_for_large_icon_service_(
+ : fetcher_for_large_icon_service_(
base::MakeUnique<::testing::StrictMock<MockImageFetcher>>()),
fetcher_for_icon_cacher_(
base::MakeUnique<::testing::StrictMock<MockImageFetcher>>()) {
@@ -453,8 +451,6 @@ class IconCacherTestMostLikely : public IconCacherTestBase {
SetDesiredImageFrameSize(gfx::Size(128, 128)));
}
- scoped_refptr<base::TestSimpleTaskRunner>
- large_icon_service_background_task_runner_;
std::unique_ptr<MockImageFetcher> fetcher_for_large_icon_service_;
std::unique_ptr<MockImageFetcher> fetcher_for_icon_cacher_;
};
@@ -467,8 +463,7 @@ TEST_F(IconCacherTestMostLikely, Cached) {
PreloadIcon(page_url, icon_url, favicon_base::TOUCH_ICON, 128, 128);
favicon::LargeIconService large_icon_service(
- &favicon_service_, large_icon_service_background_task_runner_,
- std::move(fetcher_for_large_icon_service_));
+ &favicon_service_, std::move(fetcher_for_large_icon_service_));
IconCacherImpl cacher(&favicon_service_, &large_icon_service,
std::move(fetcher_for_icon_cacher_));
@@ -502,8 +497,7 @@ TEST_F(IconCacherTestMostLikely, NotCachedAndFetchSucceeded) {
}
favicon::LargeIconService large_icon_service(
- &favicon_service_, large_icon_service_background_task_runner_,
- std::move(fetcher_for_large_icon_service_));
+ &favicon_service_, std::move(fetcher_for_large_icon_service_));
IconCacherImpl cacher(&favicon_service_, &large_icon_service,
std::move(fetcher_for_icon_cacher_));
@@ -511,7 +505,7 @@ TEST_F(IconCacherTestMostLikely, NotCachedAndFetchSucceeded) {
// Both these task runners need to be flushed in order to get |done| called by
// running the main loop.
WaitForHistoryThreadTasksToFinish();
- large_icon_service_background_task_runner_->RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
loop.Run();
EXPECT_FALSE(IconIsCachedFor(page_url, favicon_base::FAVICON));
@@ -541,8 +535,7 @@ TEST_F(IconCacherTestMostLikely, NotCachedAndFetchFailed) {
}
favicon::LargeIconService large_icon_service(
- &favicon_service_, large_icon_service_background_task_runner_,
- std::move(fetcher_for_large_icon_service_));
+ &favicon_service_, std::move(fetcher_for_large_icon_service_));
IconCacherImpl cacher(&favicon_service_, &large_icon_service,
std::move(fetcher_for_icon_cacher_));
@@ -550,7 +543,7 @@ TEST_F(IconCacherTestMostLikely, NotCachedAndFetchFailed) {
// Both these task runners need to be flushed before flushing the main thread
// queue in order to finish the work.
WaitForHistoryThreadTasksToFinish();
- large_icon_service_background_task_runner_->RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
WaitForMainThreadTasksToFinish();
EXPECT_FALSE(IconIsCachedFor(page_url, favicon_base::FAVICON));
@@ -573,8 +566,7 @@ TEST_F(IconCacherTestMostLikely, HandlesEmptyCallbacksNicely) {
.WillOnce(PassFetch(128, 128));
favicon::LargeIconService large_icon_service(
- &favicon_service_, large_icon_service_background_task_runner_,
- std::move(fetcher_for_large_icon_service_));
+ &favicon_service_, std::move(fetcher_for_large_icon_service_));
IconCacherImpl cacher(&favicon_service_, &large_icon_service,
std::move(fetcher_for_icon_cacher_));
@@ -582,7 +574,7 @@ TEST_F(IconCacherTestMostLikely, HandlesEmptyCallbacksNicely) {
// Both these task runners need to be flushed before flushing the main thread
// queue in order to finish the work.
WaitForHistoryThreadTasksToFinish();
- large_icon_service_background_task_runner_->RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
WaitForMainThreadTasksToFinish();
// Even though the callbacks are not called, the icon gets written out.
@@ -609,8 +601,7 @@ TEST_F(IconCacherTestMostLikely, NotCachedAndFetchPerformedOnlyOnce) {
}
favicon::LargeIconService large_icon_service(
- &favicon_service_, large_icon_service_background_task_runner_,
- std::move(fetcher_for_large_icon_service_));
+ &favicon_service_, std::move(fetcher_for_large_icon_service_));
IconCacherImpl cacher(&favicon_service_, &large_icon_service,
std::move(fetcher_for_icon_cacher_));
@@ -619,7 +610,7 @@ TEST_F(IconCacherTestMostLikely, NotCachedAndFetchPerformedOnlyOnce) {
// Both these task runners need to be flushed in order to get |done| called by
// running the main loop.
WaitForHistoryThreadTasksToFinish();
- large_icon_service_background_task_runner_->RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
loop.Run();
EXPECT_FALSE(IconIsCachedFor(page_url, favicon_base::FAVICON));
diff --git a/chromium/components/ntp_tiles/metrics.cc b/chromium/components/ntp_tiles/metrics.cc
index 4064c1594f3..bcd9f4a6a6d 100644
--- a/chromium/components/ntp_tiles/metrics.cc
+++ b/chromium/components/ntp_tiles/metrics.cc
@@ -23,7 +23,8 @@ const int kMaxNumTiles = 12;
// Identifiers for the various tile sources.
const char kHistogramClientName[] = "client";
const char kHistogramServerName[] = "server";
-const char kHistogramPopularName[] = "popular";
+const char kHistogramPopularName[] = "popular_fetched";
+const char kHistogramBakedInName[] = "popular_baked_in";
const char kHistogramWhitelistName[] = "whitelist";
const char kHistogramHomepageName[] = "homepage";
@@ -51,6 +52,8 @@ std::string GetSourceHistogramName(TileSource source) {
switch (source) {
case TileSource::TOP_SITES:
return kHistogramClientName;
+ case TileSource::POPULAR_BAKED_IN:
+ return kHistogramBakedInName;
case TileSource::POPULAR:
return kHistogramPopularName;
case TileSource::WHITELIST:
diff --git a/chromium/components/ntp_tiles/metrics_unittest.cc b/chromium/components/ntp_tiles/metrics_unittest.cc
index dbbe4c1e8e3..cba9de50eeb 100644
--- a/chromium/components/ntp_tiles/metrics_unittest.cc
+++ b/chromium/components/ntp_tiles/metrics_unittest.cc
@@ -71,7 +71,7 @@ TEST(RecordTileImpressionTest, ShouldRecordUmaForIcons) {
base::Bucket(/*min=*/3, /*count=*/1),
base::Bucket(/*min=*/4, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples(
- "NewTabPage.SuggestionsImpression.popular"),
+ "NewTabPage.SuggestionsImpression.popular_fetched"),
ElementsAre(base::Bucket(/*min=*/7, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType"),
ElementsAre(base::Bucket(/*min=*/ICON_REAL, /*count=*/4),
@@ -83,9 +83,10 @@ TEST(RecordTileImpressionTest, ShouldRecordUmaForIcons) {
EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType.client"),
ElementsAre(base::Bucket(/*min=*/ICON_REAL, /*count=*/3),
base::Bucket(/*min=*/ICON_COLOR, /*count=*/2)));
- EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType.popular"),
- ElementsAre(base::Bucket(/*min=*/ICON_COLOR,
- /*count=*/1)));
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("NewTabPage.TileType.popular_fetched"),
+ ElementsAre(base::Bucket(/*min=*/ICON_COLOR,
+ /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples(
"NewTabPage.SuggestionsImpression.IconsReal"),
ElementsAre(base::Bucket(/*min=*/0, /*count=*/1),
@@ -124,7 +125,7 @@ TEST(RecordTileImpressionTest, ShouldRecordUmaForThumbnails) {
histogram_tester.GetAllSamples("NewTabPage.SuggestionsImpression.client"),
ElementsAre(base::Bucket(/*min=*/0, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples(
- "NewTabPage.SuggestionsImpression.popular"),
+ "NewTabPage.SuggestionsImpression.popular_fetched"),
ElementsAre(base::Bucket(/*min=*/2, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType"),
ElementsAre(base::Bucket(/*min=*/THUMBNAIL, /*count=*/2),
@@ -133,8 +134,9 @@ TEST(RecordTileImpressionTest, ShouldRecordUmaForThumbnails) {
ElementsAre(base::Bucket(/*min=*/THUMBNAIL, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType.client"),
ElementsAre(base::Bucket(/*min=*/THUMBNAIL_FAILED, /*count=*/1)));
- EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType.popular"),
- ElementsAre(base::Bucket(/*min=*/THUMBNAIL, /*count=*/1)));
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("NewTabPage.TileType.popular_fetched"),
+ ElementsAre(base::Bucket(/*min=*/THUMBNAIL, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples(
"NewTabPage.SuggestionsImpression.IconsReal"),
IsEmpty());
@@ -155,8 +157,9 @@ TEST(RecordTileClickTest, ShouldRecordUmaForIcon) {
ElementsAre(base::Bucket(/*min=*/3, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.server"),
IsEmpty());
- EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.popular"),
- IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("NewTabPage.MostVisited.popular_fetched"),
+ IsEmpty());
EXPECT_THAT(
histogram_tester.GetAllSamples("NewTabPage.MostVisited.IconsReal"),
ElementsAre(base::Bucket(/*min=*/3, /*count=*/1)));
@@ -183,8 +186,9 @@ TEST(RecordTileClickTest, ShouldRecordUmaForThumbnail) {
ElementsAre(base::Bucket(/*min=*/3, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.server"),
IsEmpty());
- EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.popular"),
- IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("NewTabPage.MostVisited.popular_fetched"),
+ IsEmpty());
EXPECT_THAT(
histogram_tester.GetAllSamples("NewTabPage.MostVisited.IconsReal"),
IsEmpty());
@@ -212,8 +216,9 @@ TEST(RecordTileClickTest, ShouldNotRecordUnknownTileType) {
ElementsAre(base::Bucket(/*min=*/3, /*count=*/1)));
EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.server"),
IsEmpty());
- EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.popular"),
- IsEmpty());
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("NewTabPage.MostVisited.popular_fetched"),
+ IsEmpty());
// But all of the tile type histograms should be empty.
EXPECT_THAT(
histogram_tester.GetAllSamples("NewTabPage.MostVisited.IconsReal"),
diff --git a/chromium/components/ntp_tiles/most_visited_sites.cc b/chromium/components/ntp_tiles/most_visited_sites.cc
index 45a4bcddbb8..7327615bab2 100644
--- a/chromium/components/ntp_tiles/most_visited_sites.cc
+++ b/chromium/components/ntp_tiles/most_visited_sites.cc
@@ -5,12 +5,14 @@
#include "components/ntp_tiles/most_visited_sites.h"
#include <algorithm>
+#include <iterator>
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "base/feature_list.h"
#include "base/metrics/user_metrics.h"
+#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/history/core/browser/top_sites.h"
#include "components/ntp_tiles/constants.h"
@@ -33,13 +35,27 @@ namespace {
const base::Feature kDisplaySuggestionsServiceTiles{
"DisplaySuggestionsServiceTiles", base::FEATURE_ENABLED_BY_DEFAULT};
-// The maximum index of the home page tile.
-const size_t kMaxHomeTileIndex = 3;
+// URL host prefixes. Hosts with these prefixes often redirect to each other, or
+// have the same content.
+// Popular sites are excluded if the user has visited a page whose host only
+// differs by one of these prefixes. Even if the URL does not point to the exact
+// same page, the user will have a personalized suggestion that is more likely
+// to be of use for them.
+// A cleaner way could be checking the history for redirects but this requires
+// the page to be visited on the device.
+const char* kKnownGenericPagePrefixes[] = {
+ "m.", "mobile.", // Common prefixes among popular sites.
+ "edition.", // Used among news papers (CNN, Independent, ...)
+ "www.", // Usually no-www domains redirect to www or vice-versa.
+ // The following entry MUST REMAIN LAST as it is prefix of every string!
+ ""}; // The no-www domain matches domains on same level .
// Determine whether we need any tiles from PopularSites to fill up a grid of
-// |num_tiles| tiles.
+// |num_tiles| tiles. If exploration sections are used, we need popular sites
+// regardless of how many tiles we already have.
bool NeedPopularSites(const PrefService* prefs, int num_tiles) {
- return prefs->GetInteger(prefs::kNumPersonalTiles) < num_tiles;
+ return base::FeatureList::IsEnabled(kSiteExplorationUiFeature) ||
+ prefs->GetInteger(prefs::kNumPersonalTiles) < num_tiles;
}
bool AreURLsEquivalent(const GURL& url1, const GURL& url2) {
@@ -56,6 +72,16 @@ bool HasHomeTile(const NTPTilesVector& tiles) {
return false;
}
+std::string StripFirstGenericPrefix(const std::string& host) {
+ for (const char* prefix : kKnownGenericPagePrefixes) {
+ if (base::StartsWith(host, prefix, base::CompareCase::INSENSITIVE_ASCII)) {
+ return std::string(
+ base::TrimString(host, prefix, base::TrimPositions::TRIM_LEADING));
+ }
+ }
+ return host;
+}
+
} // namespace
MostVisitedSites::MostVisitedSites(
@@ -89,12 +115,27 @@ MostVisitedSites::~MostVisitedSites() {
supervisor_->SetObserver(nullptr);
}
+// static
+bool MostVisitedSites::IsHostOrMobilePageKnown(
+ const std::set<std::string>& hosts_to_skip,
+ const std::string& host) {
+ std::string no_prefix_host = StripFirstGenericPrefix(host);
+ for (const char* prefix : kKnownGenericPagePrefixes) {
+ if (hosts_to_skip.count(prefix + no_prefix_host) ||
+ hosts_to_skip.count(prefix + host)) {
+ return true;
+ }
+ }
+ return false;
+}
+
bool MostVisitedSites::DoesSourceExist(TileSource source) const {
switch (source) {
case TileSource::TOP_SITES:
return top_sites_ != nullptr;
case TileSource::SUGGESTIONS_SERVICE:
return suggestions_service_ != nullptr;
+ case TileSource::POPULAR_BAKED_IN:
case TileSource::POPULAR:
return popular_sites_ != nullptr;
case TileSource::WHITELIST:
@@ -128,10 +169,6 @@ void MostVisitedSites::SetMostVisitedURLsObserver(Observer* observer,
}
if (top_sites_) {
- // TopSites updates itself after a delay. To ensure up-to-date results,
- // force an update now.
- top_sites_->SyncWithHistory();
-
// Register as TopSitesObserver so that we can update ourselves when the
// TopSites changes.
top_sites_observer_.Add(top_sites_.get());
@@ -148,6 +185,14 @@ void MostVisitedSites::SetMostVisitedURLsObserver(Observer* observer,
}
void MostVisitedSites::Refresh() {
+ if (top_sites_) {
+ // TopSites updates itself after a delay. To ensure up-to-date results,
+ // force an update now.
+ // TODO(mastiz): Is seems unnecessary to refresh TopSites if we will end up
+ // using server-side suggestions.
+ top_sites_->SyncWithHistory();
+ }
+
suggestions_service_->FetchSuggestionsData();
}
@@ -345,38 +390,66 @@ NTPTilesVector MostVisitedSites::CreateWhitelistEntryPointTiles(
return whitelist_tiles;
}
-NTPTilesVector MostVisitedSites::CreatePopularSitesTiles(
+std::map<SectionType, NTPTilesVector>
+MostVisitedSites::CreatePopularSitesSections(
const std::set<std::string>& used_hosts,
size_t num_actual_tiles) {
+ std::map<SectionType, NTPTilesVector> sections = {
+ std::make_pair(SectionType::PERSONALIZED, NTPTilesVector())};
// For child accounts popular sites tiles will not be added.
if (supervisor_ && supervisor_->IsChildProfile()) {
- return NTPTilesVector();
+ return sections;
}
if (!popular_sites_ || !ShouldShowPopularSites()) {
- return NTPTilesVector();
+ return sections;
+ }
+
+ const std::set<std::string> no_hosts;
+ for (const auto& section_type_and_sites : popular_sites()->sections()) {
+ SectionType type = section_type_and_sites.first;
+ const PopularSites::SitesVector& sites = section_type_and_sites.second;
+ if (type == SectionType::PERSONALIZED) {
+ size_t num_required_tiles = num_sites_ - num_actual_tiles;
+ sections[type] =
+ CreatePopularSitesTiles(/*popular_sites=*/sites,
+ /*hosts_to_skip=*/used_hosts,
+ /*num_max_tiles=*/num_required_tiles);
+ } else {
+ sections[type] = CreatePopularSitesTiles(/*popular_sites=*/sites,
+ /*hosts_to_skip=*/no_hosts,
+ /*num_max_tiles=*/num_sites_);
+ }
}
+ return sections;
+}
+NTPTilesVector MostVisitedSites::CreatePopularSitesTiles(
+ const PopularSites::SitesVector& sites_vector,
+ const std::set<std::string>& hosts_to_skip,
+ size_t num_max_tiles) {
// Collect non-blacklisted popular suggestions, skipping those already present
// in the personal suggestions.
NTPTilesVector popular_sites_tiles;
- for (const PopularSites::Site& popular_site : popular_sites_->sites()) {
- if (popular_sites_tiles.size() + num_actual_tiles >= num_sites_)
+ for (const PopularSites::Site& popular_site : sites_vector) {
+ if (popular_sites_tiles.size() >= num_max_tiles) {
break;
+ }
// Skip blacklisted sites.
if (top_sites_ && top_sites_->IsBlacklisted(popular_site.url))
continue;
const std::string& host = popular_site.url.host();
- // Skip tiles already present in personal or whitelists.
- if (used_hosts.find(host) != used_hosts.end())
+ if (IsHostOrMobilePageKnown(hosts_to_skip, host)) {
continue;
+ }
NTPTile tile;
tile.title = popular_site.title;
tile.url = GURL(popular_site.url);
- tile.source = TileSource::POPULAR;
+ tile.source = popular_site.baked_in ? TileSource::POPULAR_BAKED_IN
+ : TileSource::POPULAR;
popular_sites_tiles.push_back(std::move(tile));
base::Closure icon_available =
base::Bind(&MostVisitedSites::OnIconMadeAvailable,
@@ -404,38 +477,34 @@ NTPTilesVector MostVisitedSites::InsertHomeTile(
const GURL& home_page_url = home_page_client_->GetHomePageUrl();
NTPTilesVector new_tiles;
- // Add the home tile to the first four tiles.
- NTPTile home_tile;
- home_tile.url = home_page_url;
- home_tile.title = title;
- home_tile.source = TileSource::HOMEPAGE;
-
bool home_tile_added = false;
- size_t index = 0;
- while (index < tiles.size() && new_tiles.size() < num_sites_) {
- bool hosts_are_equal = tiles[index].url.host() == home_page_url.host();
+ for (auto& tile : tiles) {
+ if (new_tiles.size() >= num_sites_) {
+ break;
+ }
- // Add the home tile to the first four tiles
- // or at the position of a tile that has the same host
- // and is ranked higher.
// TODO(fhorschig): Introduce a more sophisticated deduplication.
- if (!home_tile_added && (index >= kMaxHomeTileIndex || hosts_are_equal)) {
- new_tiles.push_back(std::move(home_tile));
+ if (tile.url.host() == home_page_url.host()) {
+ tile.source = TileSource::HOMEPAGE;
home_tile_added = true;
- continue; // Do not advance the current tile index.
- }
-
- // Add non-home page tiles.
- if (!hosts_are_equal) {
- new_tiles.push_back(std::move(tiles[index]));
}
- ++index;
+ new_tiles.push_back(std::move(tile));
}
// Add the home page tile if there are less than 4 tiles
// and none of them is the home page (and there is space left).
- if (!home_tile_added && new_tiles.size() < num_sites_) {
+ if (!home_tile_added) {
+ // Make room for the home page tile.
+ if (new_tiles.size() >= num_sites_) {
+ new_tiles.pop_back();
+ }
+
+ NTPTile home_tile;
+ home_tile.url = home_page_url;
+ home_tile.title = title;
+ home_tile.source = TileSource::HOMEPAGE;
+
new_tiles.push_back(std::move(home_tile));
}
return new_tiles;
@@ -463,13 +532,14 @@ void MostVisitedSites::SaveTilesAndNotify(NTPTilesVector personal_tiles) {
CreateWhitelistEntryPointTiles(used_hosts, num_actual_tiles);
AddToHostsAndTotalCount(whitelist_tiles, &used_hosts, &num_actual_tiles);
- NTPTilesVector popular_sites_tiles =
- CreatePopularSitesTiles(used_hosts, num_actual_tiles);
- AddToHostsAndTotalCount(popular_sites_tiles, &used_hosts, &num_actual_tiles);
+ std::map<SectionType, NTPTilesVector> sections =
+ CreatePopularSitesSections(used_hosts, num_actual_tiles);
+ AddToHostsAndTotalCount(sections[SectionType::PERSONALIZED], &used_hosts,
+ &num_actual_tiles);
NTPTilesVector new_tiles =
MergeTiles(std::move(personal_tiles), std::move(whitelist_tiles),
- std::move(popular_sites_tiles));
+ std::move(sections[SectionType::PERSONALIZED]));
if (current_tiles_.has_value() && (*current_tiles_ == new_tiles)) {
return;
}
@@ -483,10 +553,10 @@ void MostVisitedSites::SaveTilesAndNotify(NTPTilesVector personal_tiles) {
num_personal_tiles++;
}
prefs_->SetInteger(prefs::kNumPersonalTiles, num_personal_tiles);
-
if (!observer_)
return;
- observer_->OnMostVisitedURLsAvailable(*current_tiles_);
+ sections[SectionType::PERSONALIZED] = *current_tiles_;
+ observer_->OnURLsAvailable(sections);
}
// static
@@ -509,10 +579,12 @@ void MostVisitedSites::OnPopularSitesDownloaded(bool success) {
return;
}
- for (const PopularSites::Site& popular_site : popular_sites_->sites()) {
- // Ignore callback; these icons will be seen on the *next* NTP.
- icon_cacher_->StartFetchPopularSites(popular_site, base::Closure(),
- base::Closure());
+ for (const auto& section : popular_sites_->sections()) {
+ for (const PopularSites::Site& site : section.second) {
+ // Ignore callback; these icons will be seen on the *next* NTP.
+ icon_cacher_->StartFetchPopularSites(site, base::Closure(),
+ base::Closure());
+ }
}
}
diff --git a/chromium/components/ntp_tiles/most_visited_sites.h b/chromium/components/ntp_tiles/most_visited_sites.h
index 661623d30d4..2331c58f3ca 100644
--- a/chromium/components/ntp_tiles/most_visited_sites.h
+++ b/chromium/components/ntp_tiles/most_visited_sites.h
@@ -7,6 +7,7 @@
#include <stddef.h>
+#include <map>
#include <memory>
#include <set>
#include <string>
@@ -15,6 +16,7 @@
#include "base/callback_forward.h"
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
+#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
@@ -24,6 +26,7 @@
#include "components/history/core/browser/top_sites_observer.h"
#include "components/ntp_tiles/ntp_tile.h"
#include "components/ntp_tiles/popular_sites.h"
+#include "components/ntp_tiles/section_type.h"
#include "components/ntp_tiles/tile_source.h"
#include "components/suggestions/proto/suggestions.pb.h"
#include "components/suggestions/suggestions_service.h"
@@ -85,7 +88,9 @@ class MostVisitedSites : public history::TopSitesObserver,
// The observer to be notified when the list of most visited sites changes.
class Observer {
public:
- virtual void OnMostVisitedURLsAvailable(const NTPTilesVector& tiles) = 0;
+ // |sections| must at least contain the PERSONALIZED section.
+ virtual void OnURLsAvailable(
+ const std::map<SectionType, NTPTilesVector>& sections) = 0;
virtual void OnIconMadeAvailable(const GURL& site_url) = 0;
protected:
@@ -165,6 +170,22 @@ class MostVisitedSites : public history::TopSitesObserver,
NTPTilesVector popular_tiles);
private:
+ FRIEND_TEST_ALL_PREFIXES(MostVisitedSitesTest,
+ ShouldDeduplicateDomainWithNoWwwDomain);
+ FRIEND_TEST_ALL_PREFIXES(MostVisitedSitesTest,
+ ShouldDeduplicateDomainByRemovingMobilePrefixes);
+ FRIEND_TEST_ALL_PREFIXES(MostVisitedSitesTest,
+ ShouldDeduplicateDomainByReplacingMobilePrefixes);
+
+ // This function tries to match the given |host| to a close fit in
+ // |hosts_to_skip| by removing a prefix that is commonly used to redirect from
+ // or to mobile pages (m.xyz.com --> xyz.com).
+ // If this approach fails, the prefix is replaced by another prefix.
+ // That way, true is returned for m.x.com if www.x.com is in |hosts_to_skip|.
+ static bool IsHostOrMobilePageKnown(
+ const std::set<std::string>& hosts_to_skip,
+ const std::string& host);
+
// Initialize the query to Top Sites. Called if the SuggestionsService
// returned no data.
void InitiateTopSitesQuery();
@@ -193,11 +214,19 @@ class MostVisitedSites : public history::TopSitesObserver,
const std::set<std::string>& used_hosts,
size_t num_actual_tiles);
- // Creates popular tiles whose hosts weren't used yet.
- NTPTilesVector CreatePopularSitesTiles(
+ // Creates tiles for all popular site sections. Uses |num_actual_tiles| and
+ // |used_hosts| to restrict results for the PERSONALIZED section.
+ std::map<SectionType, NTPTilesVector> CreatePopularSitesSections(
const std::set<std::string>& used_hosts,
size_t num_actual_tiles);
+ // Creates tiles for |sites_vector|. The returned vector will neither contain
+ // more than |num_max_tiles| nor include sites in |hosts_to_skip|.
+ NTPTilesVector CreatePopularSitesTiles(
+ const PopularSites::SitesVector& sites_vector,
+ const std::set<std::string>& hosts_to_skip,
+ size_t num_max_tiles);
+
// Initiates a query for the home page tile if needed and calls
// |SaveTilesAndNotify| in the end.
void InitiateNotificationForNewTiles(NTPTilesVector new_tiles);
diff --git a/chromium/components/ntp_tiles/most_visited_sites_unittest.cc b/chromium/components/ntp_tiles/most_visited_sites_unittest.cc
index 43bdea7dc97..0eb30120ee7 100644
--- a/chromium/components/ntp_tiles/most_visited_sites_unittest.cc
+++ b/chromium/components/ntp_tiles/most_visited_sites_unittest.cc
@@ -6,6 +6,7 @@
#include <stddef.h>
+#include <map>
#include <memory>
#include <ostream>
#include <string>
@@ -29,6 +30,7 @@
#include "components/ntp_tiles/json_unsafe_parser.h"
#include "components/ntp_tiles/popular_sites_impl.h"
#include "components/ntp_tiles/pref_names.h"
+#include "components/ntp_tiles/section_type.h"
#include "components/ntp_tiles/switches.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "net/url_request/test_url_fetcher_factory.h"
@@ -59,11 +61,14 @@ using testing::ByMove;
using testing::Contains;
using testing::ElementsAre;
using testing::Eq;
+using testing::Ge;
using testing::InSequence;
using testing::Invoke;
using testing::IsEmpty;
+using testing::Key;
using testing::Mock;
using testing::Not;
+using testing::Pair;
using testing::Return;
using testing::ReturnRef;
using testing::SaveArg;
@@ -87,13 +92,17 @@ MATCHER_P3(MatchesTile, title, url, source, PrintTile(title, url, source)) {
arg.source == source;
}
-MATCHER_P3(FirstTileIs,
+MATCHER_P3(FirstPersonalizedTileIs,
title,
url,
source,
std::string("first tile ") + PrintTile(title, url, source)) {
- return !arg.empty() && arg[0].title == base::ASCIIToUTF16(title) &&
- arg[0].url == GURL(url) && arg[0].source == source;
+ if (arg.count(SectionType::PERSONALIZED) == 0) {
+ return false;
+ }
+ const NTPTilesVector& tiles = arg.at(SectionType::PERSONALIZED);
+ return !tiles.empty() && tiles[0].title == base::ASCIIToUTF16(title) &&
+ tiles[0].url == GURL(url) && tiles[0].source == source;
}
// testing::InvokeArgument<N> does not work with base::Callback, fortunately
@@ -208,7 +217,8 @@ class MockSuggestionsService : public SuggestionsService {
class MockMostVisitedSitesObserver : public MostVisitedSites::Observer {
public:
- MOCK_METHOD1(OnMostVisitedURLsAvailable, void(const NTPTilesVector& tiles));
+ MOCK_METHOD1(OnURLsAvailable,
+ void(const std::map<SectionType, NTPTilesVector>& sections));
MOCK_METHOD1(OnIconMadeAvailable, void(const GURL& site_url));
};
@@ -273,10 +283,10 @@ class PopularSitesFactoryForTest {
PopularSitesImpl::RegisterProfilePrefs(pref_service->registry());
if (enabled) {
prefs_->SetString(prefs::kPopularSitesOverrideCountry, "IN");
- prefs_->SetString(prefs::kPopularSitesOverrideVersion, "7");
+ prefs_->SetString(prefs::kPopularSitesOverrideVersion, "5");
url_fetcher_factory_.SetFakeResponse(
- GURL("https://www.gstatic.com/chrome/ntp/suggested_sites_IN_7.json"),
+ GURL("https://www.gstatic.com/chrome/ntp/suggested_sites_IN_5.json"),
R"([{
"title": "PopularSite1",
"url": "http://popularsite1/",
@@ -289,6 +299,70 @@ class PopularSitesFactoryForTest {
},
])",
net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+
+ url_fetcher_factory_.SetFakeResponse(
+ GURL("https://www.gstatic.com/chrome/ntp/suggested_sites_US_5.json"),
+ R"([{
+ "title": "ESPN",
+ "url": "http://www.espn.com",
+ "favicon_url": "http://www.espn.com/favicon.ico"
+ }, {
+ "title": "Mobile",
+ "url": "http://www.mobile.de",
+ "favicon_url": "http://www.mobile.de/favicon.ico"
+ }, {
+ "title": "Google News",
+ "url": "http://news.google.com",
+ "favicon_url": "http://news.google.com/favicon.ico"
+ },
+ ])",
+ net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+
+ url_fetcher_factory_.SetFakeResponse(
+ GURL("https://www.gstatic.com/chrome/ntp/suggested_sites_IN_6.json"),
+ R"([{
+ "section": 1, // PERSONALIZED
+ "sites": [{
+ "title": "PopularSite1",
+ "url": "http://popularsite1/",
+ "favicon_url": "http://popularsite1/favicon.ico"
+ },
+ {
+ "title": "PopularSite2",
+ "url": "http://popularsite2/",
+ "favicon_url": "http://popularsite2/favicon.ico"
+ },
+ ]
+ },
+ {
+ "section": 4, // NEWS
+ "sites": [{
+ "large_icon_url": "https://news.google.com/icon.ico",
+ "title": "Google News",
+ "url": "https://news.google.com/"
+ },
+ {
+ "favicon_url": "https://news.google.com/icon.ico",
+ "title": "Google News Germany",
+ "url": "https://news.google.de/"
+ }]
+ },
+ {
+ "section": 2, // SOCIAL
+ "sites": [{
+ "large_icon_url": "https://ssl.gstatic.com/icon.png",
+ "title": "Google+",
+ "url": "https://plus.google.com/"
+ }]
+ },
+ {
+ "section": 3, // ENTERTAINMENT
+ "sites": [
+ // Intentionally empty site list.
+ ]
+ }
+ ])",
+ net::HTTP_OK, net::URLRequestStatus::SUCCESS);
}
}
@@ -330,6 +404,8 @@ class TopSitesCallbackList {
std::vector<TopSites::GetMostVisitedURLsCallback> callbacks_;
};
+} // namespace
+
// Param specifies whether Popular Sites is enabled via variations.
class MostVisitedSitesTest : public ::testing::TestWithParam<bool> {
protected:
@@ -350,6 +426,10 @@ class MostVisitedSitesTest : public ::testing::TestWithParam<bool> {
feature_list_.InitAndDisableFeature(
kNtpMostLikelyFaviconsFromServerFeature);
+ RecreateMostVisitedSites();
+ }
+
+ void RecreateMostVisitedSites() {
// We use StrictMock to make sure the object is not used unless Popular
// Sites is enabled.
auto icon_cacher = base::MakeUnique<StrictMock<MockIconCacher>>();
@@ -444,6 +524,12 @@ TEST_P(MostVisitedSitesTest, ShouldStartNoCallInConstructor) {
base::RunLoop().RunUntilIdle();
}
+TEST_P(MostVisitedSitesTest, ShouldRefreshBothBackends) {
+ EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
+ EXPECT_CALL(mock_suggestions_service_, FetchSuggestionsData());
+ most_visited_sites_->Refresh();
+}
+
TEST_P(MostVisitedSitesTest, ShouldIncludeTileForHomePage) {
FakeHomePageClient* home_page_client = RegisterNewHomePageClient();
home_page_client->SetHomePageEnabled(true);
@@ -454,7 +540,7 @@ TEST_P(MostVisitedSitesTest, ShouldIncludeTileForHomePage) {
EXPECT_CALL(*mock_top_sites_, IsBlacklisted(Eq(GURL(kHomePageUrl))))
.Times(AnyNumber())
.WillRepeatedly(Return(false));
- EXPECT_CALL(mock_observer_, OnMostVisitedURLsAvailable(FirstTileIs(
+ EXPECT_CALL(mock_observer_, OnURLsAvailable(FirstPersonalizedTileIs(
"", kHomePageUrl, TileSource::HOMEPAGE)));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/3);
@@ -467,8 +553,10 @@ TEST_P(MostVisitedSitesTest, ShouldNotIncludeHomePageWithoutClient) {
.WillRepeatedly(InvokeCallbackArgument<0>(MostVisitedURLList{}));
EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(Not(Contains(
- MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE)))));
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ Not(Contains(MatchesTile("", kHomePageUrl,
+ TileSource::HOMEPAGE)))))));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/3);
base::RunLoop().RunUntilIdle();
@@ -491,11 +579,15 @@ TEST_P(MostVisitedSitesTest, ShouldIncludeHomeTileWithUrlBeforeQueryingName) {
{
testing::Sequence seq;
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(Not(Contains(
- MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE)))));
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ Not(Contains(MatchesTile("", kHomePageUrl,
+ TileSource::HOMEPAGE)))))));
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(Not(Contains(MatchesTile(
- kHomePageTitle, kHomePageUrl, TileSource::HOMEPAGE)))));
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ Not(Contains(MatchesTile(kHomePageTitle, kHomePageUrl,
+ TileSource::HOMEPAGE)))))));
}
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/3);
@@ -514,7 +606,7 @@ TEST_P(MostVisitedSitesTest, ShouldUpdateHomePageTileOnHomePageStateChanged) {
EXPECT_CALL(*mock_top_sites_, IsBlacklisted(Eq(GURL(kHomePageUrl))))
.Times(AnyNumber())
.WillRepeatedly(Return(false));
- EXPECT_CALL(mock_observer_, OnMostVisitedURLsAvailable(FirstTileIs(
+ EXPECT_CALL(mock_observer_, OnURLsAvailable(FirstPersonalizedTileIs(
"", kHomePageUrl, TileSource::HOMEPAGE)));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/3);
@@ -527,7 +619,7 @@ TEST_P(MostVisitedSitesTest, ShouldUpdateHomePageTileOnHomePageStateChanged) {
EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_, false))
.WillRepeatedly(InvokeCallbackArgument<0>(MostVisitedURLList{}));
EXPECT_CALL(*mock_top_sites_, SyncWithHistory()).Times(0);
- EXPECT_CALL(mock_observer_, OnMostVisitedURLsAvailable(Not(FirstTileIs(
+ EXPECT_CALL(mock_observer_, OnURLsAvailable(Not(FirstPersonalizedTileIs(
"", kHomePageUrl, TileSource::HOMEPAGE))));
most_visited_sites_->OnHomePageStateChanged();
base::RunLoop().RunUntilIdle();
@@ -543,13 +635,15 @@ TEST_P(MostVisitedSitesTest, ShouldNotIncludeHomePageIfNoTileRequested) {
EXPECT_CALL(*mock_top_sites_, IsBlacklisted(Eq(GURL(kHomePageUrl))))
.Times(AnyNumber())
.WillRepeatedly(Return(false));
- EXPECT_CALL(mock_observer_, OnMostVisitedURLsAvailable(IsEmpty()));
+ EXPECT_CALL(
+ mock_observer_,
+ OnURLsAvailable(Contains(Pair(SectionType::PERSONALIZED, IsEmpty()))));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/0);
base::RunLoop().RunUntilIdle();
}
-TEST_P(MostVisitedSitesTest, ShouldReturnMostPopularPageIfOneTileRequested) {
+TEST_P(MostVisitedSitesTest, ShouldReturnHomePageIfOneTileRequested) {
FakeHomePageClient* home_page_client = RegisterNewHomePageClient();
home_page_client->SetHomePageEnabled(true);
DisableRemoteSuggestions();
@@ -560,15 +654,17 @@ TEST_P(MostVisitedSitesTest, ShouldReturnMostPopularPageIfOneTileRequested) {
EXPECT_CALL(*mock_top_sites_, IsBlacklisted(Eq(GURL(kHomePageUrl))))
.Times(AnyNumber())
.WillRepeatedly(Return(false));
- EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(MatchesTile(
- "Site 1", "http://site1/", TileSource::TOP_SITES))));
+ EXPECT_CALL(
+ mock_observer_,
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE))))));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/1);
base::RunLoop().RunUntilIdle();
}
-TEST_P(MostVisitedSitesTest, ShouldContainHomePageInFirstFourTiles) {
+TEST_P(MostVisitedSitesTest, ShouldReplaceLastTileWithHomePageWhenFull) {
FakeHomePageClient* home_page_client = RegisterNewHomePageClient();
home_page_client->SetHomePageEnabled(true);
DisableRemoteSuggestions();
@@ -584,16 +680,48 @@ TEST_P(MostVisitedSitesTest, ShouldContainHomePageInFirstFourTiles) {
EXPECT_CALL(*mock_top_sites_, IsBlacklisted(Eq(GURL(kHomePageUrl))))
.Times(AnyNumber())
.WillRepeatedly(Return(false));
- std::vector<NTPTile> tiles;
- EXPECT_CALL(mock_observer_, OnMostVisitedURLsAvailable(_))
- .WillOnce(SaveArg<0>(&tiles));
+ std::map<SectionType, NTPTilesVector> sections;
+ EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
+ .WillOnce(SaveArg<0>(&sections));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
- /*num_sites=*/8);
+ /*num_sites=*/4);
base::RunLoop().RunUntilIdle();
- // Assert that the home page tile is in the first four tiles.
+ ASSERT_THAT(sections, Contains(Key(SectionType::PERSONALIZED)));
+ NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
+ ASSERT_THAT(tiles.size(), Ge(4ul));
+ // Assert that the home page is appended as the final tile.
EXPECT_THAT(tiles[3], MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE));
}
+TEST_P(MostVisitedSitesTest, ShouldAppendHomePageWhenNotFull) {
+ FakeHomePageClient* home_page_client = RegisterNewHomePageClient();
+ home_page_client->SetHomePageEnabled(true);
+ DisableRemoteSuggestions();
+ EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_, false))
+ .WillRepeatedly(InvokeCallbackArgument<0>((MostVisitedURLList{
+ MakeMostVisitedURL("Site 1", "http://site1/"),
+ MakeMostVisitedURL("Site 2", "http://site2/"),
+ MakeMostVisitedURL("Site 3", "http://site3/"),
+ MakeMostVisitedURL("Site 4", "http://site4/"),
+ MakeMostVisitedURL("Site 5", "http://site5/"),
+ })));
+ EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
+ EXPECT_CALL(*mock_top_sites_, IsBlacklisted(Eq(GURL(kHomePageUrl))))
+ .Times(AnyNumber())
+ .WillRepeatedly(Return(false));
+ std::map<SectionType, NTPTilesVector> sections;
+ EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
+ .WillOnce(SaveArg<0>(&sections));
+ most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
+ /*num_sites=*/8);
+ base::RunLoop().RunUntilIdle();
+ ASSERT_THAT(sections, Contains(Key(SectionType::PERSONALIZED)));
+ NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
+ ASSERT_THAT(tiles.size(), Ge(6ul));
+ // Assert that the home page is appended as the final tile.
+ EXPECT_THAT(tiles[5], MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE));
+}
+
TEST_P(MostVisitedSitesTest, ShouldDeduplicateHomePageWithTopSites) {
FakeHomePageClient* home_page_client = RegisterNewHomePageClient();
home_page_client->SetHomePageEnabled(true);
@@ -606,11 +734,13 @@ TEST_P(MostVisitedSitesTest, ShouldDeduplicateHomePageWithTopSites) {
EXPECT_CALL(*mock_top_sites_, IsBlacklisted(Eq(GURL(kHomePageUrl))))
.Times(AnyNumber())
.WillRepeatedly(Return(false));
- EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(AllOf(
- Contains(MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE)),
- Not(Contains(
- MatchesTile("", kHomePageUrl, TileSource::TOP_SITES))))));
+ EXPECT_CALL(
+ mock_observer_,
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ AllOf(Contains(MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE)),
+ Not(Contains(
+ MatchesTile("", kHomePageUrl, TileSource::TOP_SITES))))))));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/3);
base::RunLoop().RunUntilIdle();
@@ -628,8 +758,10 @@ TEST_P(MostVisitedSitesTest, ShouldNotIncludeHomePageIfItIsNewTabPage) {
.Times(AnyNumber())
.WillRepeatedly(Return(false));
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(Not(Contains(
- MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE)))));
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ Not(Contains(MatchesTile("", kHomePageUrl,
+ TileSource::HOMEPAGE)))))));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/3);
base::RunLoop().RunUntilIdle();
@@ -646,8 +778,10 @@ TEST_P(MostVisitedSitesTest, ShouldNotIncludeHomePageIfThereIsNone) {
.Times(AnyNumber())
.WillRepeatedly(Return(false));
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(Not(Contains(
- MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE)))));
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ Not(Contains(MatchesTile("", kHomePageUrl,
+ TileSource::HOMEPAGE)))))));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/3);
base::RunLoop().RunUntilIdle();
@@ -666,8 +800,8 @@ TEST_P(MostVisitedSitesTest, ShouldNotIncludeHomePageIfEmptyUrl) {
.Times(AnyNumber())
.WillRepeatedly(Return(false));
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(Not(
- FirstTileIs("", kEmptyHomePageUrl, TileSource::HOMEPAGE))));
+ OnURLsAvailable(Not(FirstPersonalizedTileIs(
+ "", kEmptyHomePageUrl, TileSource::HOMEPAGE))));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/3);
base::RunLoop().RunUntilIdle();
@@ -689,8 +823,10 @@ TEST_P(MostVisitedSitesTest, ShouldNotIncludeHomePageIfBlacklisted) {
.Times(AtLeast(1))
.WillRepeatedly(Return(true));
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(Not(Contains(
- MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE)))));
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ Not(Contains(MatchesTile("", kHomePageUrl,
+ TileSource::HOMEPAGE)))))));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/3);
@@ -710,8 +846,10 @@ TEST_P(MostVisitedSitesTest, ShouldPinHomePageAgainIfBlacklistingUndone) {
.Times(AtLeast(1))
.WillRepeatedly(Return(true));
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(Not(Contains(
- MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE)))));
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ Not(Contains(MatchesTile("", kHomePageUrl,
+ TileSource::HOMEPAGE)))))));
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/3);
@@ -724,8 +862,11 @@ TEST_P(MostVisitedSitesTest, ShouldPinHomePageAgainIfBlacklistingUndone) {
EXPECT_CALL(*mock_top_sites_, IsBlacklisted(Eq(GURL(kHomePageUrl))))
.Times(AtLeast(1))
.WillRepeatedly(Return(false));
- EXPECT_CALL(mock_observer_, OnMostVisitedURLsAvailable(Contains(MatchesTile(
- "", kHomePageUrl, TileSource::HOMEPAGE))));
+ EXPECT_CALL(
+ mock_observer_,
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ Contains(MatchesTile("", kHomePageUrl, TileSource::HOMEPAGE))))));
most_visited_sites_->OnBlockedSitesChanged();
base::RunLoop().RunUntilIdle();
@@ -747,6 +888,89 @@ TEST_P(MostVisitedSitesTest, ShouldInformSuggestionSourcesWhenBlacklisting) {
/*add_url=*/false);
}
+TEST_P(MostVisitedSitesTest, ShouldContainSiteExplorationsWhenFeatureEnabled) {
+ base::test::ScopedFeatureList feature_list;
+ std::map<SectionType, NTPTilesVector> sections;
+ feature_list.InitAndEnableFeature(kSiteExplorationUiFeature);
+ pref_service_.SetString(prefs::kPopularSitesOverrideVersion, "6");
+ RecreateMostVisitedSites(); // Refills cache with version 6 popular sites.
+ DisableRemoteSuggestions();
+ EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_, false))
+ .WillRepeatedly(InvokeCallbackArgument<0>(
+ MostVisitedURLList{MakeMostVisitedURL("Site 1", "http://site1/")}));
+ EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
+ EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
+ .WillOnce(SaveArg<0>(&sections));
+
+ most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
+ /*num_sites=*/3);
+ base::RunLoop().RunUntilIdle();
+
+ if (!IsPopularSitesEnabledViaVariations()) {
+ EXPECT_THAT(
+ sections,
+ Contains(Pair(SectionType::PERSONALIZED,
+ ElementsAre(MatchesTile("Site 1", "http://site1/",
+ TileSource::TOP_SITES)))));
+ return;
+ }
+ const auto& expected_sections =
+ most_visited_sites_->popular_sites()->sections();
+ ASSERT_THAT(expected_sections.size(), Ge(2ul));
+ EXPECT_THAT(sections.size(), Eq(expected_sections.size()));
+ EXPECT_THAT(
+ sections,
+ AllOf(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(MatchesTile("Site 1", "http://site1/",
+ TileSource::TOP_SITES),
+ MatchesTile("PopularSite1", "http://popularsite1/",
+ TileSource::POPULAR),
+ MatchesTile("PopularSite2", "http://popularsite2/",
+ TileSource::POPULAR)))),
+ Contains(Pair(SectionType::NEWS, SizeIs(2ul))),
+ Contains(Pair(SectionType::SOCIAL, SizeIs(1ul))),
+ Contains(Pair(_, IsEmpty()))));
+}
+
+TEST_P(MostVisitedSitesTest,
+ ShouldDeduplicatePopularSitesWithMostVisitedIffHostAndTitleMatches) {
+ pref_service_.SetString(prefs::kPopularSitesOverrideCountry, "US");
+ RecreateMostVisitedSites(); // Refills cache with ESPN and Google News.
+ DisableRemoteSuggestions();
+ EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_, false))
+ .WillRepeatedly(InvokeCallbackArgument<0>(MostVisitedURLList{
+ MakeMostVisitedURL("ESPN", "http://espn.com/"),
+ MakeMostVisitedURL("Mobile", "http://m.mobile.de/"),
+ MakeMostVisitedURL("Google", "http://www.google.com/")}));
+ EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
+ std::map<SectionType, NTPTilesVector> sections;
+ EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
+ .WillOnce(SaveArg<0>(&sections));
+
+ most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
+ /*num_sites=*/6);
+ base::RunLoop().RunUntilIdle();
+ ASSERT_THAT(sections, Contains(Key(SectionType::PERSONALIZED)));
+ EXPECT_THAT(sections.at(SectionType::PERSONALIZED),
+ Contains(MatchesTile("Google", "http://www.google.com/",
+ TileSource::TOP_SITES)));
+ if (IsPopularSitesEnabledViaVariations()) {
+ EXPECT_THAT(sections.at(SectionType::PERSONALIZED),
+ Contains(MatchesTile("Google News", "http://news.google.com/",
+ TileSource::POPULAR)));
+ }
+ EXPECT_THAT(sections.at(SectionType::PERSONALIZED),
+ AllOf(Contains(MatchesTile("ESPN", "http://espn.com/",
+ TileSource::TOP_SITES)),
+ Contains(MatchesTile("Mobile", "http://m.mobile.de/",
+ TileSource::TOP_SITES)),
+ Not(Contains(MatchesTile("ESPN", "http://www.espn.com/",
+ TileSource::POPULAR))),
+ Not(Contains(MatchesTile("Mobile", "http://www.mobile.de/",
+ TileSource::POPULAR)))));
+}
+
TEST_P(MostVisitedSitesTest, ShouldHandleTopSitesCacheHit) {
// If cached, TopSites returns the tiles synchronously, running the callback
// even before the function returns.
@@ -755,7 +979,6 @@ TEST_P(MostVisitedSitesTest, ShouldHandleTopSitesCacheHit) {
MostVisitedURLList{MakeMostVisitedURL("Site 1", "http://site1/")}));
InSequence seq;
- EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
EXPECT_CALL(mock_suggestions_service_, AddCallback(_))
.WillOnce(Invoke(&suggestions_service_callbacks_,
&SuggestionsService::ResponseCallbackList::Add));
@@ -764,17 +987,22 @@ TEST_P(MostVisitedSitesTest, ShouldHandleTopSitesCacheHit) {
if (IsPopularSitesEnabledViaVariations()) {
EXPECT_CALL(
mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
- MatchesTile("PopularSite1", "http://popularsite1/",
- TileSource::POPULAR),
- MatchesTile("PopularSite2", "http://popularsite2/",
- TileSource::POPULAR))));
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(
+ MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
+ MatchesTile("PopularSite1", "http://popularsite1/",
+ TileSource::POPULAR),
+ MatchesTile("PopularSite2", "http://popularsite2/",
+ TileSource::POPULAR))))));
} else {
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(MatchesTile(
- "Site 1", "http://site1/", TileSource::TOP_SITES))));
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ ElementsAre(MatchesTile("Site 1", "http://site1/",
+ TileSource::TOP_SITES))))));
}
+ EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
EXPECT_CALL(mock_suggestions_service_, FetchSuggestionsData())
.WillOnce(Return(true));
@@ -792,7 +1020,7 @@ TEST_P(MostVisitedSitesTest, ShouldHandleTopSitesCacheHit) {
EXPECT_CALL(*mock_top_sites_, IsBlacklisted(_))
.WillRepeatedly(Return(false));
}
- EXPECT_CALL(mock_observer_, OnMostVisitedURLsAvailable(_));
+ EXPECT_CALL(mock_observer_, OnURLsAvailable(_));
mock_top_sites_->NotifyTopSitesChanged(
history::TopSitesObserver::ChangeReason::MOST_VISITED);
base::RunLoop().RunUntilIdle();
@@ -802,13 +1030,47 @@ INSTANTIATE_TEST_CASE_P(MostVisitedSitesTest,
MostVisitedSitesTest,
::testing::Bool());
+TEST(MostVisitedSitesTest, ShouldDeduplicateDomainWithNoWwwDomain) {
+ EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"www.mobile.de"},
+ "mobile.de"));
+ EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"mobile.de"},
+ "www.mobile.de"));
+ EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"mobile.co.uk"},
+ "www.mobile.co.uk"));
+}
+
+TEST(MostVisitedSitesTest, ShouldDeduplicateDomainByRemovingMobilePrefixes) {
+ EXPECT_TRUE(
+ MostVisitedSites::IsHostOrMobilePageKnown({"bbc.co.uk"}, "m.bbc.co.uk"));
+ EXPECT_TRUE(
+ MostVisitedSites::IsHostOrMobilePageKnown({"m.bbc.co.uk"}, "bbc.co.uk"));
+ EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"cnn.com"},
+ "edition.cnn.com"));
+ EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"edition.cnn.com"},
+ "cnn.com"));
+ EXPECT_TRUE(
+ MostVisitedSites::IsHostOrMobilePageKnown({"cnn.com"}, "mobile.cnn.com"));
+ EXPECT_TRUE(
+ MostVisitedSites::IsHostOrMobilePageKnown({"mobile.cnn.com"}, "cnn.com"));
+}
+
+TEST(MostVisitedSitesTest, ShouldDeduplicateDomainByReplacingMobilePrefixes) {
+ EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"www.bbc.co.uk"},
+ "m.bbc.co.uk"));
+ EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"m.mobile.de"},
+ "www.mobile.de"));
+ EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"www.cnn.com"},
+ "edition.cnn.com"));
+ EXPECT_TRUE(MostVisitedSites::IsHostOrMobilePageKnown({"mobile.cnn.com"},
+ "www.cnn.com"));
+}
+
class MostVisitedSitesWithCacheHitTest : public MostVisitedSitesTest {
public:
// Constructor sets the common expectations for the case where suggestions
// service has cached results when the observer is registered.
MostVisitedSitesWithCacheHitTest() {
InSequence seq;
- EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
EXPECT_CALL(mock_suggestions_service_, AddCallback(_))
.WillOnce(Invoke(&suggestions_service_callbacks_,
&SuggestionsService::ResponseCallbackList::Add));
@@ -818,27 +1080,33 @@ class MostVisitedSitesWithCacheHitTest : public MostVisitedSitesTest {
MakeSuggestion("Site 2", "http://site2/"),
MakeSuggestion("Site 3", "http://site3/"),
})));
+
if (IsPopularSitesEnabledViaVariations()) {
- EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/",
- TileSource::SUGGESTIONS_SERVICE),
- MatchesTile("Site 2", "http://site2/",
- TileSource::SUGGESTIONS_SERVICE),
- MatchesTile("Site 3", "http://site3/",
- TileSource::SUGGESTIONS_SERVICE),
- MatchesTile("PopularSite1", "http://popularsite1/",
- TileSource::POPULAR))));
+ EXPECT_CALL(
+ mock_observer_,
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(MatchesTile("Site 1", "http://site1/",
+ TileSource::SUGGESTIONS_SERVICE),
+ MatchesTile("Site 2", "http://site2/",
+ TileSource::SUGGESTIONS_SERVICE),
+ MatchesTile("Site 3", "http://site3/",
+ TileSource::SUGGESTIONS_SERVICE),
+ MatchesTile("PopularSite1", "http://popularsite1/",
+ TileSource::POPULAR))))));
} else {
- EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/",
- TileSource::SUGGESTIONS_SERVICE),
- MatchesTile("Site 2", "http://site2/",
- TileSource::SUGGESTIONS_SERVICE),
- MatchesTile("Site 3", "http://site3/",
- TileSource::SUGGESTIONS_SERVICE))));
+ EXPECT_CALL(
+ mock_observer_,
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(MatchesTile("Site 1", "http://site1/",
+ TileSource::SUGGESTIONS_SERVICE),
+ MatchesTile("Site 2", "http://site2/",
+ TileSource::SUGGESTIONS_SERVICE),
+ MatchesTile("Site 3", "http://site3/",
+ TileSource::SUGGESTIONS_SERVICE))))));
}
+ EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
EXPECT_CALL(mock_suggestions_service_, FetchSuggestionsData())
.WillOnce(Return(true));
@@ -858,7 +1126,8 @@ TEST_P(MostVisitedSitesWithCacheHitTest, ShouldFavorSuggestionsServiceCache) {
TEST_P(MostVisitedSitesWithCacheHitTest,
ShouldPropagateUpdateBySuggestionsService) {
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
ElementsAre(MatchesTile("Site 4", "http://site4/",
TileSource::SUGGESTIONS_SERVICE),
MatchesTile("Site 5", "http://site5/",
@@ -866,7 +1135,7 @@ TEST_P(MostVisitedSitesWithCacheHitTest,
MatchesTile("Site 6", "http://site6/",
TileSource::SUGGESTIONS_SERVICE),
MatchesTile("Site 7", "http://site7/",
- TileSource::SUGGESTIONS_SERVICE))));
+ TileSource::SUGGESTIONS_SERVICE))))));
suggestions_service_callbacks_.Notify(
MakeProfile({MakeSuggestion("Site 4", "http://site4/"),
MakeSuggestion("Site 5", "http://site5/"),
@@ -876,7 +1145,9 @@ TEST_P(MostVisitedSitesWithCacheHitTest,
}
TEST_P(MostVisitedSitesWithCacheHitTest, ShouldTruncateList) {
- EXPECT_CALL(mock_observer_, OnMostVisitedURLsAvailable(SizeIs(4)));
+ EXPECT_CALL(
+ mock_observer_,
+ OnURLsAvailable(Contains(Pair(SectionType::PERSONALIZED, SizeIs(4)))));
suggestions_service_callbacks_.Notify(
MakeProfile({MakeSuggestion("Site 4", "http://site4/"),
MakeSuggestion("Site 5", "http://site5/"),
@@ -889,19 +1160,23 @@ TEST_P(MostVisitedSitesWithCacheHitTest, ShouldTruncateList) {
TEST_P(MostVisitedSitesWithCacheHitTest,
ShouldCompleteWithPopularSitesIffEnabled) {
if (IsPopularSitesEnabledViaVariations()) {
- EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 4", "http://site4/",
- TileSource::SUGGESTIONS_SERVICE),
- MatchesTile("PopularSite1", "http://popularsite1/",
- TileSource::POPULAR),
- MatchesTile("PopularSite2", "http://popularsite2/",
- TileSource::POPULAR))));
+ EXPECT_CALL(
+ mock_observer_,
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ ElementsAre(MatchesTile("Site 4", "http://site4/",
+ TileSource::SUGGESTIONS_SERVICE),
+ MatchesTile("PopularSite1", "http://popularsite1/",
+ TileSource::POPULAR),
+ MatchesTile("PopularSite2", "http://popularsite2/",
+ TileSource::POPULAR))))));
} else {
EXPECT_CALL(
mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(MatchesTile(
- "Site 4", "http://site4/", TileSource::SUGGESTIONS_SERVICE))));
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ ElementsAre(MatchesTile("Site 4", "http://site4/",
+ TileSource::SUGGESTIONS_SERVICE))))));
}
suggestions_service_callbacks_.Notify(
MakeProfile({MakeSuggestion("Site 4", "http://site4/")}));
@@ -917,11 +1192,14 @@ TEST_P(MostVisitedSitesWithCacheHitTest,
EXPECT_CALL(
mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 4", "http://site4/", TileSource::TOP_SITES),
- MatchesTile("Site 5", "http://site5/", TileSource::TOP_SITES),
- MatchesTile("Site 6", "http://site6/", TileSource::TOP_SITES),
- MatchesTile("Site 7", "http://site7/", TileSource::TOP_SITES))));
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(
+ MatchesTile("Site 4", "http://site4/", TileSource::TOP_SITES),
+ MatchesTile("Site 5", "http://site5/", TileSource::TOP_SITES),
+ MatchesTile("Site 6", "http://site6/", TileSource::TOP_SITES),
+ MatchesTile("Site 7", "http://site7/",
+ TileSource::TOP_SITES))))));
top_sites_callbacks_.ClearAndNotify(
{MakeMostVisitedURL("Site 4", "http://site4/"),
MakeMostVisitedURL("Site 5", "http://site5/"),
@@ -934,7 +1212,7 @@ TEST_P(MostVisitedSitesWithCacheHitTest, ShouldFetchFaviconsIfEnabled) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(kNtpMostLikelyFaviconsFromServerFeature);
- EXPECT_CALL(mock_observer_, OnMostVisitedURLsAvailable(_));
+ EXPECT_CALL(mock_observer_, OnURLsAvailable(_));
EXPECT_CALL(*icon_cacher_, StartFetchMostLikely(GURL("http://site4/"), _));
suggestions_service_callbacks_.Notify(
@@ -952,7 +1230,6 @@ class MostVisitedSitesWithEmptyCacheTest : public MostVisitedSitesTest {
// service doesn't have cached results when the observer is registered.
MostVisitedSitesWithEmptyCacheTest() {
InSequence seq;
- EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
EXPECT_CALL(mock_suggestions_service_, AddCallback(_))
.WillOnce(Invoke(&suggestions_service_callbacks_,
&SuggestionsService::ResponseCallbackList::Add));
@@ -960,6 +1237,7 @@ class MostVisitedSitesWithEmptyCacheTest : public MostVisitedSitesTest {
.WillOnce(Return(SuggestionsProfile())); // Empty cache.
EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_, false))
.WillOnce(Invoke(&top_sites_callbacks_, &TopSitesCallbackList::Add));
+ EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
EXPECT_CALL(mock_suggestions_service_, FetchSuggestionsData())
.WillOnce(Return(true));
@@ -980,19 +1258,23 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
TEST_P(MostVisitedSitesWithEmptyCacheTest,
ShouldCompleteWithPopularSitesIffEnabled) {
if (IsPopularSitesEnabledViaVariations()) {
- EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 4", "http://site4/",
- TileSource::SUGGESTIONS_SERVICE),
- MatchesTile("PopularSite1", "http://popularsite1/",
- TileSource::POPULAR),
- MatchesTile("PopularSite2", "http://popularsite2/",
- TileSource::POPULAR))));
+ EXPECT_CALL(
+ mock_observer_,
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ ElementsAre(MatchesTile("Site 4", "http://site4/",
+ TileSource::SUGGESTIONS_SERVICE),
+ MatchesTile("PopularSite1", "http://popularsite1/",
+ TileSource::POPULAR),
+ MatchesTile("PopularSite2", "http://popularsite2/",
+ TileSource::POPULAR))))));
} else {
EXPECT_CALL(
mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(MatchesTile(
- "Site 4", "http://site4/", TileSource::SUGGESTIONS_SERVICE))));
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ ElementsAre(MatchesTile("Site 4", "http://site4/",
+ TileSource::SUGGESTIONS_SERVICE))))));
}
suggestions_service_callbacks_.Notify(
MakeProfile({MakeSuggestion("Site 4", "http://site4/")}));
@@ -1003,13 +1285,14 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
ShouldIgnoreTopSitesIfSuggestionsServiceFaster) {
// Reply from suggestions service triggers and update to our observer.
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
ElementsAre(MatchesTile("Site 1", "http://site1/",
TileSource::SUGGESTIONS_SERVICE),
MatchesTile("Site 2", "http://site2/",
TileSource::SUGGESTIONS_SERVICE),
MatchesTile("Site 3", "http://site3/",
- TileSource::SUGGESTIONS_SERVICE))));
+ TileSource::SUGGESTIONS_SERVICE))))));
suggestions_service_callbacks_.Notify(
MakeProfile({MakeSuggestion("Site 1", "http://site1/"),
MakeSuggestion("Site 2", "http://site2/"),
@@ -1036,10 +1319,13 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
// Reply from top sites is propagated to observer.
EXPECT_CALL(
mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
- MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
- MatchesTile("Site 3", "http://site3/", TileSource::TOP_SITES))));
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(
+ MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
+ MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
+ MatchesTile("Site 3", "http://site3/",
+ TileSource::TOP_SITES))))));
top_sites_callbacks_.ClearAndNotify(
{MakeMostVisitedURL("Site 1", "http://site1/"),
MakeMostVisitedURL("Site 2", "http://site2/"),
@@ -1052,10 +1338,13 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
// Reply from top sites is propagated to observer.
EXPECT_CALL(
mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
- MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
- MatchesTile("Site 3", "http://site3/", TileSource::TOP_SITES))));
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(
+ MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
+ MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
+ MatchesTile("Site 3", "http://site3/",
+ TileSource::TOP_SITES))))));
top_sites_callbacks_.ClearAndNotify(
{MakeMostVisitedURL("Site 1", "http://site1/"),
MakeMostVisitedURL("Site 2", "http://site2/"),
@@ -1065,13 +1354,14 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
// Reply from suggestions service overrides top sites.
InSequence seq;
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
ElementsAre(MatchesTile("Site 4", "http://site4/",
TileSource::SUGGESTIONS_SERVICE),
MatchesTile("Site 5", "http://site5/",
TileSource::SUGGESTIONS_SERVICE),
MatchesTile("Site 6", "http://site6/",
- TileSource::SUGGESTIONS_SERVICE))));
+ TileSource::SUGGESTIONS_SERVICE))))));
suggestions_service_callbacks_.Notify(
MakeProfile({MakeSuggestion("Site 4", "http://site4/"),
MakeSuggestion("Site 5", "http://site5/"),
@@ -1084,10 +1374,13 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
// Reply from top sites is propagated to observer.
EXPECT_CALL(
mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
- MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
- MatchesTile("Site 3", "http://site3/", TileSource::TOP_SITES))));
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(
+ MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
+ MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
+ MatchesTile("Site 3", "http://site3/",
+ TileSource::TOP_SITES))))));
top_sites_callbacks_.ClearAndNotify(
{MakeMostVisitedURL("Site 1", "http://site1/"),
MakeMostVisitedURL("Site 2", "http://site2/"),
@@ -1103,10 +1396,13 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest, ShouldPropagateUpdateByTopSites) {
// Reply from top sites is propagated to observer.
EXPECT_CALL(
mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
- MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
- MatchesTile("Site 3", "http://site3/", TileSource::TOP_SITES))));
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(
+ MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
+ MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
+ MatchesTile("Site 3", "http://site3/",
+ TileSource::TOP_SITES))))));
top_sites_callbacks_.ClearAndNotify(
{MakeMostVisitedURL("Site 1", "http://site1/"),
MakeMostVisitedURL("Site 2", "http://site2/"),
@@ -1126,10 +1422,13 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest, ShouldPropagateUpdateByTopSites) {
MakeMostVisitedURL("Site 6", "http://site6/")}));
EXPECT_CALL(
mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 4", "http://site4/", TileSource::TOP_SITES),
- MatchesTile("Site 5", "http://site5/", TileSource::TOP_SITES),
- MatchesTile("Site 6", "http://site6/", TileSource::TOP_SITES))));
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(
+ MatchesTile("Site 4", "http://site4/", TileSource::TOP_SITES),
+ MatchesTile("Site 5", "http://site5/", TileSource::TOP_SITES),
+ MatchesTile("Site 6", "http://site6/",
+ TileSource::TOP_SITES))))));
mock_top_sites_->NotifyTopSitesChanged(
history::TopSitesObserver::ChangeReason::MOST_VISITED);
base::RunLoop().RunUntilIdle();
@@ -1138,16 +1437,19 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest, ShouldPropagateUpdateByTopSites) {
TEST_P(MostVisitedSitesWithEmptyCacheTest,
ShouldSendEmptyListIfBothTopSitesAndSuggestionsServiceEmpty) {
if (IsPopularSitesEnabledViaVariations()) {
- EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("PopularSite1", "http://popularsite1/",
- TileSource::POPULAR),
- MatchesTile("PopularSite2", "http://popularsite2/",
- TileSource::POPULAR))));
+ EXPECT_CALL(
+ mock_observer_,
+ OnURLsAvailable(Contains(
+ Pair(SectionType::PERSONALIZED,
+ ElementsAre(MatchesTile("PopularSite1", "http://popularsite1/",
+ TileSource::POPULAR),
+ MatchesTile("PopularSite2", "http://popularsite2/",
+ TileSource::POPULAR))))));
} else {
// The Android NTP doesn't finish initialization until it gets tiles, so a
// 0-tile notification is always needed.
- EXPECT_CALL(mock_observer_, OnMostVisitedURLsAvailable(IsEmpty()));
+ EXPECT_CALL(mock_observer_, OnURLsAvailable(ElementsAre(Pair(
+ SectionType::PERSONALIZED, IsEmpty()))));
}
suggestions_service_callbacks_.Notify(SuggestionsProfile());
top_sites_callbacks_.ClearAndNotify(MostVisitedURLList{});
@@ -1159,10 +1461,13 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
ShouldNotifyOnceIfTopSitesUnchanged) {
EXPECT_CALL(
mock_observer_,
- OnMostVisitedURLsAvailable(ElementsAre(
- MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
- MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
- MatchesTile("Site 3", "http://site3/", TileSource::TOP_SITES))));
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
+ ElementsAre(
+ MatchesTile("Site 1", "http://site1/", TileSource::TOP_SITES),
+ MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES),
+ MatchesTile("Site 3", "http://site3/",
+ TileSource::TOP_SITES))))));
suggestions_service_callbacks_.Notify(SuggestionsProfile());
@@ -1189,13 +1494,14 @@ TEST_P(MostVisitedSitesWithEmptyCacheTest,
TEST_P(MostVisitedSitesWithEmptyCacheTest,
ShouldNotifyOnceIfSuggestionsUnchanged) {
EXPECT_CALL(mock_observer_,
- OnMostVisitedURLsAvailable(
+ OnURLsAvailable(Contains(Pair(
+ SectionType::PERSONALIZED,
ElementsAre(MatchesTile("Site 1", "http://site1/",
TileSource::SUGGESTIONS_SERVICE),
MatchesTile("Site 2", "http://site2/",
TileSource::SUGGESTIONS_SERVICE),
MatchesTile("Site 3", "http://site3/",
- TileSource::SUGGESTIONS_SERVICE))));
+ TileSource::SUGGESTIONS_SERVICE))))));
for (int i = 0; i < 5; ++i) {
suggestions_service_callbacks_.Notify(
@@ -1282,5 +1588,4 @@ TEST(MostVisitedSitesMergeTest, ShouldMergeTilesFavoringPersonalOverPopular) {
TileSource::POPULAR)));
}
-} // namespace
} // namespace ntp_tiles
diff --git a/chromium/components/ntp_tiles/popular_sites.h b/chromium/components/ntp_tiles/popular_sites.h
index f1e207fcac1..7e6b21db219 100644
--- a/chromium/components/ntp_tiles/popular_sites.h
+++ b/chromium/components/ntp_tiles/popular_sites.h
@@ -5,12 +5,14 @@
#ifndef COMPONENTS_NTP_TILES_POPULAR_SITES_H_
#define COMPONENTS_NTP_TILES_POPULAR_SITES_H_
+#include <map>
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/macros.h"
#include "base/strings/string16.h"
+#include "components/ntp_tiles/section_type.h"
#include "url/gurl.h"
namespace base {
@@ -37,6 +39,7 @@ class PopularSites {
GURL favicon_url;
GURL large_icon_url;
GURL thumbnail_url;
+ bool baked_in;
int default_icon_resource; // < 0 if there is none. Used for popular sites.
};
@@ -60,8 +63,8 @@ class PopularSites {
virtual bool MaybeStartFetch(bool force_download,
const FinishedCallback& callback) = 0;
- // Returns the list of available sites.
- virtual const SitesVector& sites() const = 0;
+ // Returns the cached list of available sections and their sites.
+ virtual const std::map<SectionType, SitesVector>& sections() const = 0;
// Various internals exposed publicly for diagnostic pages only.
virtual GURL GetLastURLFetched() const = 0;
diff --git a/chromium/components/ntp_tiles/popular_sites_impl.cc b/chromium/components/ntp_tiles/popular_sites_impl.cc
index 38fc464509b..c238ab8867a 100644
--- a/chromium/components/ntp_tiles/popular_sites_impl.cc
+++ b/chromium/components/ntp_tiles/popular_sites_impl.cc
@@ -5,13 +5,16 @@
#include "components/ntp_tiles/popular_sites_impl.h"
#include <stddef.h>
+#include <map>
#include <utility>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/feature_list.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/values.h"
#include "build/build_config.h"
@@ -53,12 +56,9 @@ const char kPopularSitesURLFormat[] =
const char kPopularSitesDefaultDirectory[] = "chrome/ntp/";
const char kPopularSitesDefaultCountryCode[] = "DEFAULT";
const char kPopularSitesDefaultVersion[] = "5";
+const int kSitesExplorationStartVersion = 6;
const int kPopularSitesRedownloadIntervalHours = 24;
-const char kPopularSitesLastDownloadPref[] = "popular_sites_last_download";
-const char kPopularSitesURLPref[] = "popular_sites_url";
-const char kPopularSitesJsonPref[] = "suggested_sites_json";
-
GURL GetPopularSitesURL(const std::string& directory,
const std::string& country,
const std::string& version) {
@@ -128,10 +128,65 @@ PopularSites::SitesVector ParseSiteList(const base::ListValue& list) {
GURL(large_icon_url), GURL(thumbnail_url));
item->GetInteger("default_icon_resource",
&sites.back().default_icon_resource);
+ item->GetBoolean("baked_in", &sites.back().baked_in);
}
return sites;
}
+std::map<SectionType, PopularSites::SitesVector> ParseVersion5(
+ const base::ListValue& list) {
+ return {{SectionType::PERSONALIZED, ParseSiteList(list)}};
+}
+
+std::map<SectionType, PopularSites::SitesVector> ParseVersion6OrAbove(
+ const base::ListValue& list) {
+ // Valid lists would have contained at least the PERSONALIZED section.
+ std::map<SectionType, PopularSites::SitesVector> sections = {
+ std::make_pair(SectionType::PERSONALIZED, PopularSites::SitesVector{})};
+ for (size_t i = 0; i < list.GetSize(); i++) {
+ const base::DictionaryValue* item;
+ if (!list.GetDictionary(i, &item)) {
+ LOG(WARNING) << "Parsed SitesExploration list contained an invalid "
+ << "section at position " << i << ".";
+ continue;
+ }
+ int section;
+ if (!item->GetInteger("section", &section) || section < 0 ||
+ section > static_cast<int>(SectionType::LAST)) {
+ LOG(WARNING) << "Parsed SitesExploration list contained a section with "
+ << "invalid ID (" << section << ")";
+ continue;
+ }
+ SectionType section_type = static_cast<SectionType>(section);
+ if (section_type == SectionType::UNKNOWN) {
+ LOG(WARNING) << "Dropped an unknown section in SitesExploration list.";
+ continue;
+ }
+ const base::ListValue* sites_list;
+ if (!item->GetList("sites", &sites_list)) {
+ continue;
+ }
+ sections[section_type] = ParseSiteList(*sites_list);
+ }
+ if (!base::FeatureList::IsEnabled(kSiteExplorationUiFeature)) {
+ // New versions of popular sites that should act like old versions will
+ // mimic having only the personalized list.
+ return {std::make_pair(SectionType::PERSONALIZED,
+ std::move(sections[SectionType::PERSONALIZED]))};
+ }
+ return sections;
+}
+
+std::map<SectionType, PopularSites::SitesVector> ParseSites(
+ const base::ListValue& list,
+ int version) {
+ if (version >= kSitesExplorationStartVersion) {
+ return ParseVersion6OrAbove(list);
+ } else {
+ return ParseVersion5(list);
+ }
+}
+
#if defined(GOOGLE_CHROME_BUILD) && (defined(OS_ANDROID) || defined(OS_IOS))
void SetDefaultResourceForSite(int index,
int resource_id,
@@ -157,6 +212,10 @@ std::unique_ptr<base::ListValue> DefaultPopularSites() {
ResourceBundle::GetSharedInstance().GetRawDataResource(
IDR_DEFAULT_POPULAR_SITES_JSON)));
DCHECK(sites);
+ for (base::Value& site : *sites) {
+ base::DictionaryValue& dict = static_cast<base::DictionaryValue&>(site);
+ dict.SetBoolean("baked_in", true);
+ }
#if defined(GOOGLE_CHROME_BUILD)
int index = 0;
for (int icon_resource :
@@ -183,6 +242,7 @@ PopularSites::Site::Site(const base::string16& title,
favicon_url(favicon_url),
large_icon_url(large_icon_url),
thumbnail_url(thumbnail_url),
+ baked_in(false),
default_icon_resource(-1) {}
PopularSites::Site::Site(const Site& other) = default;
@@ -201,7 +261,9 @@ PopularSitesImpl::PopularSitesImpl(
download_context_(download_context),
parse_json_(std::move(parse_json)),
is_fallback_(false),
- sites_(ParseSiteList(*prefs->GetList(kPopularSitesJsonPref))),
+ sections_(
+ ParseSites(*prefs->GetList(prefs::kPopularSitesJsonPref),
+ prefs_->GetInteger(prefs::kPopularSitesVersionPref))),
weak_ptr_factory_(this) {}
PopularSitesImpl::~PopularSitesImpl() {}
@@ -212,7 +274,7 @@ bool PopularSitesImpl::MaybeStartFetch(bool force_download,
callback_ = callback;
const base::Time last_download_time = base::Time::FromInternalValue(
- prefs_->GetInt64(kPopularSitesLastDownloadPref));
+ prefs_->GetInt64(prefs::kPopularSitesLastDownloadPref));
const base::TimeDelta time_since_last_download =
base::Time::Now() - last_download_time;
const base::TimeDelta redownload_interval =
@@ -221,7 +283,7 @@ bool PopularSitesImpl::MaybeStartFetch(bool force_download,
pending_url_ = GetURLToFetch();
const bool url_changed =
- pending_url_.spec() != prefs_->GetString(kPopularSitesURLPref);
+ pending_url_.spec() != prefs_->GetString(prefs::kPopularSitesURLPref);
// Download forced, or we need to download a new file.
if (force_download || download_time_is_future ||
@@ -232,18 +294,20 @@ bool PopularSitesImpl::MaybeStartFetch(bool force_download,
return false;
}
-const PopularSites::SitesVector& PopularSitesImpl::sites() const {
- return sites_;
+const std::map<SectionType, PopularSitesImpl::SitesVector>&
+PopularSitesImpl::sections() const {
+ return sections_;
}
GURL PopularSitesImpl::GetLastURLFetched() const {
- return GURL(prefs_->GetString(kPopularSitesURLPref));
+ return GURL(prefs_->GetString(prefs::kPopularSitesURLPref));
}
GURL PopularSitesImpl::GetURLToFetch() {
const std::string directory = GetDirectoryToFetch();
const std::string country = GetCountryToFetch();
const std::string version = GetVersionToFetch();
+ base::StringToInt(version, &version_in_pending_url_);
const GURL override_url =
GURL(prefs_->GetString(ntp_tiles::prefs::kPopularSitesOverrideURL));
@@ -311,7 +375,7 @@ std::string PopularSitesImpl::GetVersionToFetch() {
}
const base::ListValue* PopularSitesImpl::GetCachedJson() {
- return prefs_->GetList(kPopularSitesJsonPref);
+ return prefs_->GetList(prefs::kPopularSitesJsonPref);
}
// static
@@ -326,9 +390,13 @@ void PopularSitesImpl::RegisterProfilePrefs(
user_prefs->RegisterStringPref(ntp_tiles::prefs::kPopularSitesOverrideVersion,
std::string());
- user_prefs->RegisterInt64Pref(kPopularSitesLastDownloadPref, 0);
- user_prefs->RegisterStringPref(kPopularSitesURLPref, std::string());
- user_prefs->RegisterListPref(kPopularSitesJsonPref, DefaultPopularSites());
+ user_prefs->RegisterInt64Pref(prefs::kPopularSitesLastDownloadPref, 0);
+ user_prefs->RegisterStringPref(prefs::kPopularSitesURLPref, std::string());
+ user_prefs->RegisterListPref(prefs::kPopularSitesJsonPref,
+ DefaultPopularSites());
+ int version;
+ base::StringToInt(kPopularSitesDefaultVersion, &version);
+ user_prefs->RegisterIntegerPref(prefs::kPopularSitesVersionPref, version);
}
void PopularSitesImpl::FetchPopularSites() {
@@ -347,7 +415,7 @@ void PopularSitesImpl::FetchPopularSites() {
destination: GOOGLE_OWNED_SERVICE
}
policy {
- cookies_allowed: false
+ cookies_allowed: NO
setting: "This feature cannot be disabled in settings."
policy_exception_justification:
"Not implemented, considered not useful."
@@ -390,13 +458,13 @@ void PopularSitesImpl::OnJsonParsed(std::unique_ptr<base::Value> json) {
OnDownloadFailed();
return;
}
-
- prefs_->Set(kPopularSitesJsonPref, *list);
- prefs_->SetInt64(kPopularSitesLastDownloadPref,
+ prefs_->Set(prefs::kPopularSitesJsonPref, *list);
+ prefs_->SetInt64(prefs::kPopularSitesLastDownloadPref,
base::Time::Now().ToInternalValue());
- prefs_->SetString(kPopularSitesURLPref, pending_url_.spec());
+ prefs_->SetInteger(prefs::kPopularSitesVersionPref, version_in_pending_url_);
+ prefs_->SetString(prefs::kPopularSitesURLPref, pending_url_.spec());
- sites_ = ParseSiteList(*list);
+ sections_ = ParseSites(*list, version_in_pending_url_);
callback_.Run(true);
}
diff --git a/chromium/components/ntp_tiles/popular_sites_impl.h b/chromium/components/ntp_tiles/popular_sites_impl.h
index 116297342df..c58dbf3538d 100644
--- a/chromium/components/ntp_tiles/popular_sites_impl.h
+++ b/chromium/components/ntp_tiles/popular_sites_impl.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_NTP_TILES_POPULAR_SITES_IMPL_H_
#define COMPONENTS_NTP_TILES_POPULAR_SITES_IMPL_H_
+#include <map>
#include <memory>
#include <string>
#include <vector>
@@ -59,7 +60,7 @@ class PopularSitesImpl : public PopularSites, public net::URLFetcherDelegate {
// PopularSites implementation.
bool MaybeStartFetch(bool force_download,
const FinishedCallback& callback) override;
- const SitesVector& sites() const override;
+ const std::map<SectionType, SitesVector>& sections() const override;
GURL GetLastURLFetched() const override;
GURL GetURLToFetch() override;
std::string GetDirectoryToFetch() override;
@@ -95,8 +96,9 @@ class PopularSitesImpl : public PopularSites, public net::URLFetcherDelegate {
std::unique_ptr<net::URLFetcher> fetcher_;
bool is_fallback_;
- SitesVector sites_;
+ std::map<SectionType, SitesVector> sections_;
GURL pending_url_;
+ int version_in_pending_url_;
base::WeakPtrFactory<PopularSitesImpl> weak_ptr_factory_;
diff --git a/chromium/components/ntp_tiles/popular_sites_impl_unittest.cc b/chromium/components/ntp_tiles/popular_sites_impl_unittest.cc
index d29217f2045..17fc409c3f3 100644
--- a/chromium/components/ntp_tiles/popular_sites_impl_unittest.cc
+++ b/chromium/components/ntp_tiles/popular_sites_impl_unittest.cc
@@ -16,6 +16,7 @@
#include "base/message_loop/message_loop.h"
#include "base/optional.h"
#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
@@ -24,6 +25,7 @@
#include "components/ntp_tiles/json_unsafe_parser.h"
#include "components/ntp_tiles/pref_names.h"
#include "components/ntp_tiles/switches.h"
+#include "components/ntp_tiles/tile_source.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "net/http/http_status_code.h"
@@ -33,9 +35,15 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using testing::_;
+using testing::Contains;
+using testing::ElementsAre;
using testing::Eq;
using testing::Gt;
using testing::IsEmpty;
+using testing::Not;
+using testing::Pair;
+using testing::SizeIs;
namespace ntp_tiles {
namespace {
@@ -44,9 +52,13 @@ const char kTitle[] = "title";
const char kUrl[] = "url";
const char kLargeIconUrl[] = "large_icon_url";
const char kFaviconUrl[] = "favicon_url";
+const char kSection[] = "section";
+const char kSites[] = "sites";
using TestPopularSite = std::map<std::string, std::string>;
using TestPopularSiteVector = std::vector<TestPopularSite>;
+using TestPopularSection = std::pair<SectionType, TestPopularSiteVector>;
+using TestPopularSectionVector = std::vector<TestPopularSection>;
::testing::Matcher<const base::string16&> Str16Eq(const std::string& s) {
return ::testing::Eq(base::UTF8ToUTF16(s));
@@ -95,18 +107,38 @@ class PopularSitesTest : public ::testing::Test {
prefs_->SetString(prefs::kPopularSitesOverrideVersion, version);
}
- void RespondWithJSON(const std::string& url,
- const TestPopularSiteVector& sites) {
- base::ListValue sites_value;
+ std::unique_ptr<base::ListValue> CreateListFromTestSites(
+ const TestPopularSiteVector& sites) {
+ auto sites_value = base::MakeUnique<base::ListValue>();
for (const TestPopularSite& site : sites) {
auto site_value = base::MakeUnique<base::DictionaryValue>();
for (const std::pair<std::string, std::string>& kv : site) {
site_value->SetString(kv.first, kv.second);
}
- sites_value.Append(std::move(site_value));
+ sites_value->Append(std::move(site_value));
}
+ return sites_value;
+ }
+
+ void RespondWithV5JSON(const std::string& url,
+ const TestPopularSiteVector& sites) {
std::string sites_string;
- base::JSONWriter::Write(sites_value, &sites_string);
+ base::JSONWriter::Write(*CreateListFromTestSites(sites), &sites_string);
+ url_fetcher_factory_.SetFakeResponse(GURL(url), sites_string, net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ }
+
+ void RespondWithV6JSON(const std::string& url,
+ const TestPopularSectionVector& sections) {
+ base::ListValue sections_value;
+ for (const TestPopularSection& section : sections) {
+ auto section_value = base::MakeUnique<base::DictionaryValue>();
+ section_value->SetInteger(kSection, static_cast<int>(section.first));
+ section_value->SetList(kSites, CreateListFromTestSites(section.second));
+ sections_value.Append(std::move(section_value));
+ }
+ std::string sites_string;
+ base::JSONWriter::Write(sections_value, &sites_string);
url_fetcher_factory_.SetFakeResponse(GURL(url), sites_string, net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
}
@@ -130,6 +162,18 @@ class PopularSitesTest : public ::testing::Test {
// called at all, and if yes which was the returned bool value.
base::Optional<bool> FetchPopularSites(bool force_download,
PopularSites::SitesVector* sites) {
+ std::map<SectionType, PopularSites::SitesVector> sections;
+ base::Optional<bool> save_success =
+ FetchAllSections(force_download, &sections);
+ *sites = sections.at(SectionType::PERSONALIZED);
+ return save_success;
+ }
+
+ // Returns an optional bool representing whether the completion callback was
+ // called at all, and if yes which was the returned bool value.
+ base::Optional<bool> FetchAllSections(
+ bool force_download,
+ std::map<SectionType, PopularSites::SitesVector>* sections) {
scoped_refptr<net::TestURLRequestContextGetter> url_request_context(
new net::TestURLRequestContextGetter(
base::ThreadTaskRunnerHandle::Get()));
@@ -148,7 +192,7 @@ class PopularSitesTest : public ::testing::Test {
&save_success, &loop))) {
loop.Run();
}
- *sites = popular_sites->sites();
+ *sections = popular_sites->sections();
return save_success;
}
@@ -176,8 +220,10 @@ TEST_F(PopularSitesTest, ContainsDefaultTilesRightAfterConstruction) {
base::ThreadTaskRunnerHandle::Get()));
auto popular_sites = CreatePopularSites(url_request_context.get());
- EXPECT_THAT(popular_sites->sites().size(),
- Eq(GetNumberOfDefaultPopularSitesForPlatform()));
+ EXPECT_THAT(
+ popular_sites->sections(),
+ ElementsAre(Pair(SectionType::PERSONALIZED,
+ SizeIs(GetNumberOfDefaultPopularSitesForPlatform()))));
}
TEST_F(PopularSitesTest, IsEmptyOnConstructionIfDisabledByTrial) {
@@ -190,17 +236,18 @@ TEST_F(PopularSitesTest, IsEmptyOnConstructionIfDisabledByTrial) {
base::ThreadTaskRunnerHandle::Get()));
auto popular_sites = CreatePopularSites(url_request_context.get());
- EXPECT_THAT(popular_sites->sites().size(), Eq(0ul));
+ EXPECT_THAT(popular_sites->sections(),
+ ElementsAre(Pair(SectionType::PERSONALIZED, IsEmpty())));
}
TEST_F(PopularSitesTest, ShouldSucceedFetching) {
- SetCountryAndVersion("ZZ", "9");
- RespondWithJSON(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+ SetCountryAndVersion("ZZ", "5");
+ RespondWithV5JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
{kWikipedia});
PopularSites::SitesVector sites;
- EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
+ EXPECT_THAT(FetchPopularSites(/*force_download=*/true, &sites),
Eq(base::Optional<bool>(true)));
ASSERT_THAT(sites.size(), Eq(1u));
@@ -212,10 +259,10 @@ TEST_F(PopularSitesTest, ShouldSucceedFetching) {
}
TEST_F(PopularSitesTest, Fallback) {
- SetCountryAndVersion("ZZ", "9");
+ SetCountryAndVersion("ZZ", "5");
RespondWith404(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json");
- RespondWithJSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json");
+ RespondWithV5JSON(
"https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json",
{kYouTube, kChromium});
@@ -237,9 +284,9 @@ TEST_F(PopularSitesTest, Fallback) {
}
TEST_F(PopularSitesTest, PopulatesWithDefaultResoucesOnFailure) {
- SetCountryAndVersion("ZZ", "9");
+ SetCountryAndVersion("ZZ", "5");
RespondWith404(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json");
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json");
RespondWith404(
"https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json");
@@ -249,6 +296,7 @@ TEST_F(PopularSitesTest, PopulatesWithDefaultResoucesOnFailure) {
EXPECT_THAT(sites.size(), Eq(GetNumberOfDefaultPopularSitesForPlatform()));
}
+#if defined(OS_ANDROID) || defined(OS_IOS)
TEST_F(PopularSitesTest, AddsIconResourcesToDefaultPages) {
scoped_refptr<net::TestURLRequestContextGetter> url_request_context(
new net::TestURLRequestContextGetter(
@@ -256,18 +304,22 @@ TEST_F(PopularSitesTest, AddsIconResourcesToDefaultPages) {
std::unique_ptr<PopularSites> popular_sites =
CreatePopularSites(url_request_context.get());
-#if defined(GOOGLE_CHROME_BUILD) && (defined(OS_ANDROID) || defined(OS_IOS))
- ASSERT_FALSE(popular_sites->sites().empty());
- for (const auto& site : popular_sites->sites()) {
+ const PopularSites::SitesVector& sites =
+ popular_sites->sections().at(SectionType::PERSONALIZED);
+ ASSERT_FALSE(sites.empty());
+ for (const auto& site : sites) {
+ EXPECT_TRUE(site.baked_in);
+#if defined(GOOGLE_CHROME_BUILD)
EXPECT_THAT(site.default_icon_resource, Gt(0));
- }
#endif
+ }
}
+#endif
TEST_F(PopularSitesTest, ProvidesDefaultSitesUntilCallbackReturns) {
- SetCountryAndVersion("ZZ", "9");
- RespondWithJSON(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+ SetCountryAndVersion("ZZ", "5");
+ RespondWithV5JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
{kWikipedia});
scoped_refptr<net::TestURLRequestContextGetter> url_request_context(
new net::TestURLRequestContextGetter(
@@ -290,20 +342,21 @@ TEST_F(PopularSitesTest, ProvidesDefaultSitesUntilCallbackReturns) {
// Assert that callback was scheduled so we can wait for its completion.
ASSERT_TRUE(callback_was_scheduled);
// There should be 8 default sites as nothing was fetched yet.
- EXPECT_THAT(popular_sites->sites().size(),
+ EXPECT_THAT(popular_sites->sections().at(SectionType::PERSONALIZED).size(),
Eq(GetNumberOfDefaultPopularSitesForPlatform()));
loop.Run(); // Wait for the fetch to finish and the callback to return.
EXPECT_TRUE(save_success.value());
// The 1 fetched site should replace the default sites.
- EXPECT_THAT(popular_sites->sites().size(), Eq(1ul));
+ EXPECT_THAT(popular_sites->sections(),
+ ElementsAre(Pair(SectionType::PERSONALIZED, SizeIs(1ul))));
}
TEST_F(PopularSitesTest, UsesCachedJson) {
- SetCountryAndVersion("ZZ", "9");
- RespondWithJSON(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+ SetCountryAndVersion("ZZ", "5");
+ RespondWithV5JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
{kWikipedia});
// First request succeeds and gets cached.
@@ -313,17 +366,17 @@ TEST_F(PopularSitesTest, UsesCachedJson) {
// File disappears from server, but we don't need it because it's cached.
RespondWith404(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json");
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json");
EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Eq(base::nullopt));
EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
}
TEST_F(PopularSitesTest, CachesEmptyFile) {
- SetCountryAndVersion("ZZ", "9");
+ SetCountryAndVersion("ZZ", "5");
RespondWithData(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json", "[]");
- RespondWithJSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json", "[]");
+ RespondWithV5JSON(
"https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json",
{kWikipedia});
@@ -334,8 +387,8 @@ TEST_F(PopularSitesTest, CachesEmptyFile) {
EXPECT_THAT(sites, IsEmpty());
// File appears on server, but we continue to use our cached empty file.
- RespondWithJSON(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+ RespondWithV5JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
{kWikipedia});
EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Eq(base::nullopt));
@@ -343,9 +396,9 @@ TEST_F(PopularSitesTest, CachesEmptyFile) {
}
TEST_F(PopularSitesTest, DoesntUseCachedFileIfDownloadForced) {
- SetCountryAndVersion("ZZ", "9");
- RespondWithJSON(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+ SetCountryAndVersion("ZZ", "5");
+ RespondWithV5JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
{kWikipedia});
// First request succeeds and gets cached.
@@ -355,41 +408,65 @@ TEST_F(PopularSitesTest, DoesntUseCachedFileIfDownloadForced) {
EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
// File disappears from server. Download is forced, so we get the new file.
- RespondWithJSON(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+ RespondWithV5JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
{kChromium});
EXPECT_THAT(FetchPopularSites(/*force_download=*/true, &sites),
Eq(base::Optional<bool>(true)));
EXPECT_THAT(sites[0].url, URLEq("https://www.chromium.org/"));
}
+TEST_F(PopularSitesTest, DoesntUseCacheWithDeprecatedVersion) {
+ SetCountryAndVersion("ZZ", "5");
+ RespondWithV5JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
+ {kWikipedia});
+
+ // First request succeeds and gets cached.
+ PopularSites::SitesVector sites;
+ EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
+ Eq(base::Optional<bool>(true)));
+ EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
+ EXPECT_THAT(prefs_->GetInteger(prefs::kPopularSitesVersionPref), Eq(5));
+
+ // The client is updated to use V6. Drop old data and refetch.
+ SetCountryAndVersion("ZZ", "6");
+ RespondWithV6JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_6.json",
+ {{SectionType::PERSONALIZED, {kChromium}}});
+ EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
+ Eq(base::Optional<bool>(true)));
+ EXPECT_THAT(sites[0].url, URLEq("https://www.chromium.org/"));
+ EXPECT_THAT(prefs_->GetInteger(prefs::kPopularSitesVersionPref), Eq(6));
+}
+
TEST_F(PopularSitesTest, RefetchesAfterCountryMoved) {
- RespondWithJSON(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+ RespondWithV5JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
{kWikipedia});
- RespondWithJSON(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZX_9.json",
+ RespondWithV5JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZX_5.json",
{kChromium});
PopularSites::SitesVector sites;
// First request (in ZZ) saves Wikipedia.
- SetCountryAndVersion("ZZ", "9");
+ SetCountryAndVersion("ZZ", "5");
EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Eq(base::Optional<bool>(true)));
EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
// Second request (now in ZX) saves Chromium.
- SetCountryAndVersion("ZX", "9");
+ SetCountryAndVersion("ZX", "5");
EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
base::Optional<bool>(true));
EXPECT_THAT(sites[0].url, URLEq("https://www.chromium.org/"));
}
TEST_F(PopularSitesTest, DoesntCacheInvalidFile) {
- SetCountryAndVersion("ZZ", "9");
+ SetCountryAndVersion("ZZ", "5");
RespondWithData(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
"ceci n'est pas un json");
RespondWith404(
"https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json");
@@ -400,8 +477,8 @@ TEST_F(PopularSitesTest, DoesntCacheInvalidFile) {
Eq(base::Optional<bool>(false)));
// Second request refetches ZZ_9, which now has data.
- RespondWithJSON(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+ RespondWithV5JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
{kChromium});
EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Eq(base::Optional<bool>(true)));
@@ -410,10 +487,10 @@ TEST_F(PopularSitesTest, DoesntCacheInvalidFile) {
}
TEST_F(PopularSitesTest, RefetchesAfterFallback) {
- SetCountryAndVersion("ZZ", "9");
+ SetCountryAndVersion("ZZ", "5");
RespondWith404(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json");
- RespondWithJSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json");
+ RespondWithV5JSON(
"https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json",
{kWikipedia});
@@ -425,8 +502,8 @@ TEST_F(PopularSitesTest, RefetchesAfterFallback) {
EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
// Second request refetches ZZ_9, which now has data.
- RespondWithJSON(
- "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+ RespondWithV5JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
{kChromium});
EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Eq(base::Optional<bool>(true)));
@@ -435,10 +512,10 @@ TEST_F(PopularSitesTest, RefetchesAfterFallback) {
}
TEST_F(PopularSitesTest, ShouldOverrideDirectory) {
- SetCountryAndVersion("ZZ", "9");
+ SetCountryAndVersion("ZZ", "5");
prefs_->SetString(prefs::kPopularSitesOverrideDirectory, "foo/bar/");
- RespondWithJSON("https://www.gstatic.com/foo/bar/suggested_sites_ZZ_9.json",
- {kWikipedia});
+ RespondWithV5JSON("https://www.gstatic.com/foo/bar/suggested_sites_ZZ_5.json",
+ {kWikipedia});
PopularSites::SitesVector sites;
EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
@@ -447,5 +524,64 @@ TEST_F(PopularSitesTest, ShouldOverrideDirectory) {
EXPECT_THAT(sites.size(), Eq(1u));
}
+TEST_F(PopularSitesTest, DoesNotFetchExplorationSitesWithoutFeature) {
+ base::test::ScopedFeatureList override_features;
+ override_features.InitAndDisableFeature(kSiteExplorationUiFeature);
+
+ SetCountryAndVersion("ZZ", "6");
+ RespondWithV6JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_6.json",
+ {{SectionType::PERSONALIZED, {kChromium}},
+ {SectionType::NEWS, {kYouTube}}});
+
+ std::map<SectionType, PopularSites::SitesVector> sections;
+ EXPECT_THAT(FetchAllSections(/*force_download=*/false, &sections),
+ Eq(base::Optional<bool>(true)));
+
+ // The fetched news section should not be propagated without enabled feature.
+ EXPECT_THAT(sections, Not(Contains(Pair(SectionType::NEWS, _))));
+}
+
+TEST_F(PopularSitesTest, FetchesExplorationSitesWithFeature) {
+ base::test::ScopedFeatureList override_features;
+ override_features.InitAndEnableFeature(kSiteExplorationUiFeature);
+ SetCountryAndVersion("ZZ", "6");
+ RespondWithV6JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_6.json",
+ {{SectionType::PERSONALIZED, {kChromium}},
+ {SectionType::ENTERTAINMENT, {kWikipedia, kYouTube}},
+ {SectionType::NEWS, {kYouTube}},
+ {SectionType::TOOLS, TestPopularSiteVector{}}});
+
+ std::map<SectionType, PopularSites::SitesVector> sections;
+ EXPECT_THAT(FetchAllSections(/*force_download=*/false, &sections),
+ Eq(base::Optional<bool>(true)));
+
+ EXPECT_THAT(sections, ElementsAre(Pair(SectionType::PERSONALIZED, SizeIs(1)),
+ Pair(SectionType::ENTERTAINMENT, SizeIs(2)),
+ Pair(SectionType::NEWS, SizeIs(1)),
+ Pair(SectionType::TOOLS, IsEmpty())));
+}
+
+TEST_F(PopularSitesTest, FetchesExplorationSitesIgnoreUnknownSections) {
+ base::test::ScopedFeatureList override_features;
+ override_features.InitAndEnableFeature(kSiteExplorationUiFeature);
+
+ SetCountryAndVersion("ZZ", "6");
+ RespondWithV6JSON(
+ "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_6.json",
+ {{SectionType::UNKNOWN, {kChromium}},
+ {SectionType::NEWS, {kYouTube}},
+ {SectionType::UNKNOWN, {kWikipedia, kYouTube}}});
+
+ std::map<SectionType, PopularSites::SitesVector> sections;
+ EXPECT_THAT(FetchAllSections(/*force_download=*/false, &sections),
+ Eq(base::Optional<bool>(true)));
+
+ // Expect that there are four sections, none of which is empty.
+ EXPECT_THAT(sections, ElementsAre(Pair(SectionType::PERSONALIZED, SizeIs(0)),
+ Pair(SectionType::NEWS, SizeIs(1))));
+}
+
} // namespace
} // namespace ntp_tiles
diff --git a/chromium/components/ntp_tiles/pref_names.cc b/chromium/components/ntp_tiles/pref_names.cc
index c8839987362..409de49b546 100644
--- a/chromium/components/ntp_tiles/pref_names.cc
+++ b/chromium/components/ntp_tiles/pref_names.cc
@@ -25,5 +25,11 @@ const char kPopularSitesOverrideCountry[] = "popular_sites.override_country";
// If set, this will override the default file version for popular sites.
const char kPopularSitesOverrideVersion[] = "popular_sites.override_version";
+// Prefs used to cache suggested sites and store caching meta data.
+const char kPopularSitesLastDownloadPref[] = "popular_sites_last_download";
+const char kPopularSitesURLPref[] = "popular_sites_url";
+const char kPopularSitesJsonPref[] = "suggested_sites_json";
+const char kPopularSitesVersionPref[] = "suggested_sites_version";
+
} // namespace prefs
} // namespace ntp_tiles
diff --git a/chromium/components/ntp_tiles/pref_names.h b/chromium/components/ntp_tiles/pref_names.h
index 9c4de063cf9..687f5577b29 100644
--- a/chromium/components/ntp_tiles/pref_names.h
+++ b/chromium/components/ntp_tiles/pref_names.h
@@ -15,6 +15,11 @@ extern const char kPopularSitesOverrideDirectory[];
extern const char kPopularSitesOverrideCountry[];
extern const char kPopularSitesOverrideVersion[];
+extern const char kPopularSitesLastDownloadPref[];
+extern const char kPopularSitesURLPref[];
+extern const char kPopularSitesJsonPref[];
+extern const char kPopularSitesVersionPref[];
+
} // namespace prefs
} // namespace ntp_tiles
diff --git a/chromium/components/ntp_tiles/section_type.h b/chromium/components/ntp_tiles/section_type.h
new file mode 100644
index 00000000000..f1f9f5ca801
--- /dev/null
+++ b/chromium/components/ntp_tiles/section_type.h
@@ -0,0 +1,30 @@
+// 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_TILES_SECTION_TYPE_H_
+#define COMPONENTS_NTP_TILES_SECTION_TYPE_H_
+
+namespace ntp_tiles {
+
+// The type of a section means all its tiles originate here. Ranked descendingly
+// from most important section to least important.
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.suggestions
+// GENERATED_JAVA_CLASS_NAME_OVERRIDE: TileSectionType
+enum class SectionType {
+ UNKNOWN,
+ PERSONALIZED,
+ SOCIAL,
+ ENTERTAINMENT,
+ NEWS,
+ ECOMMERCE,
+ TOOLS,
+ TRAVEL,
+
+ LAST = TRAVEL
+};
+
+} // namespace ntp_tiles
+
+#endif // COMPONENTS_NTP_TILES_SECTION_TYPE_H_
diff --git a/chromium/components/ntp_tiles/tile_source.h b/chromium/components/ntp_tiles/tile_source.h
index 53ca5eab207..551e1f92557 100644
--- a/chromium/components/ntp_tiles/tile_source.h
+++ b/chromium/components/ntp_tiles/tile_source.h
@@ -17,6 +17,8 @@ enum class TileSource {
SUGGESTIONS_SERVICE,
// Tile is regionally popular.
POPULAR,
+ // Tile is a popular site baked into the binary.
+ POPULAR_BAKED_IN,
// Tile is on a custodian-managed whitelist.
WHITELIST,
// Tile containing the user-set home page is replacing the home page button.
diff --git a/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc b/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
index 098e7156ae7..64fbb6d2264 100644
--- a/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
+++ b/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
@@ -5,6 +5,8 @@
#include "components/ntp_tiles/webui/ntp_tiles_internals_message_handler.h"
#include <array>
+#include <utility>
+#include <vector>
#include "base/bind.h"
#include "base/callback.h"
@@ -276,10 +278,12 @@ void NTPTilesInternalsMessageHandler::SendTiles(
result);
}
-void NTPTilesInternalsMessageHandler::OnMostVisitedURLsAvailable(
- const NTPTilesVector& tiles) {
+void NTPTilesInternalsMessageHandler::OnURLsAvailable(
+ const std::map<SectionType, NTPTilesVector>& sections) {
cancelable_task_tracker_.TryCancelAll();
+ // TODO(fhorschig): Handle non-personalized tiles - https://crbug.com/753852.
+ const NTPTilesVector& tiles = sections.at(SectionType::PERSONALIZED);
if (tiles.empty()) {
SendTiles(tiles, FaviconResultMap());
return;
diff --git a/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.h b/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.h
index 4306f832692..7f42af2b571 100644
--- a/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.h
+++ b/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.h
@@ -60,7 +60,8 @@ class NTPTilesInternalsMessageHandler : public MostVisitedSites::Observer {
const FaviconResultMap& result_map);
// MostVisitedSites::Observer.
- void OnMostVisitedURLsAvailable(const NTPTilesVector& tiles) override;
+ void OnURLsAvailable(
+ const std::map<SectionType, NTPTilesVector>& sections) override;
void OnIconMadeAvailable(const GURL& site_url) override;
void OnFaviconLookupDone(const NTPTilesVector& tiles,
diff --git a/chromium/components/ntp_tiles/webui/resources/ntp_tiles_internals.html b/chromium/components/ntp_tiles/webui/resources/ntp_tiles_internals.html
index c407b726676..8e922ea74db 100644
--- a/chromium/components/ntp_tiles/webui/resources/ntp_tiles_internals.html
+++ b/chromium/components/ntp_tiles/webui/resources/ntp_tiles_internals.html
@@ -46,7 +46,7 @@ found in the LICENSE file.
<tbody jsselect="suggestionsService">
<tr jsdisplay="$this">
<td class="detail">
- <input id="suggestions-fetch" type="submit" value="Fetch"></input>
+ <input id="suggestions-fetch" type="submit" value="Fetch">
</td>
<td class="value" jscontent="status"></td>
</tr>
@@ -77,7 +77,7 @@ found in the LICENSE file.
</tr>
<tr jsdisplay="$this">
<td class="detail">
- <input id="popular-view-json" type="submit", value="View JSON"></input>
+ <input id="popular-view-json" type="submit", value="View JSON">
</td>
<td class="value"><pre id="popular-json-value" jscontent="json"></pre></td>
</tr>
@@ -96,7 +96,7 @@ found in the LICENSE file.
<td class="value" jsdisplay="!$this">no</td>
</tr>
<tr jsskip="true">
- <th colspan="2"><input id="submit-update" type="submit" value="Update"></input></th>
+ <th colspan="2"><input id="submit-update" type="submit" value="Update"></th>
</tr>
</tbody>
</table>
@@ -115,9 +115,10 @@ found in the LICENSE file.
<td class="value" jsdisplay="source == 0">TOP_SITES</td>
<td class="value" jsdisplay="source == 1">SUGGESTIONS_SERVICE</td>
<td class="value" jsdisplay="source == 2">POPULAR</td>
- <td class="value" jsdisplay="source == 3">WHITELIST</td>
- <td class="value" jsdisplay="source == 4">HOMEPAGE</td>
- <td class="value" jsdisplay="source &gt; 4">???</td>
+ <td class="value" jsdisplay="source == 3">POPULAR_BAKED_IN</td>
+ <td class="value" jsdisplay="source == 4">WHITELIST</td>
+ <td class="value" jsdisplay="source == 5">HOMEPAGE</td>
+ <td class="value" jsdisplay="source &gt; 5">???</td>
</tr>
<tr>
<td class="detail">URL</td>