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

Side by Side Diff: chrome/browser/android/ntp/most_visited_sites.cc

Issue 1983063002: Move classes to //components/ntp_tiles. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/android/ntp/most_visited_sites.h"
6
7 #include <utility>
8
9 #include "base/callback.h"
10 #include "base/command_line.h"
11 #include "base/metrics/field_trial.h"
12 #include "base/metrics/histogram.h"
13 #include "base/metrics/sparse_histogram.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/time/time.h"
19 #include "components/history/core/browser/top_sites.h"
20 #include "components/ntp_tiles/pref_names.h"
21 #include "components/ntp_tiles/switches.h"
22 #include "components/pref_registry/pref_registry_syncable.h"
23 #include "components/prefs/pref_service.h"
24 #include "components/variations/variations_associated_data.h"
25 #include "third_party/skia/include/core/SkBitmap.h"
26 #include "ui/gfx/codec/jpeg_codec.h"
27 #include "url/gurl.h"
28
29 using history::TopSites;
30 using suggestions::ChromeSuggestion;
31 using suggestions::SuggestionsProfile;
32 using suggestions::SuggestionsService;
33
34 namespace {
35
36 // Identifiers for the various tile sources.
37 const char kHistogramClientName[] = "client";
38 const char kHistogramServerName[] = "server";
39 const char kHistogramServerFormat[] = "server%d";
40 const char kHistogramPopularName[] = "popular";
41 const char kHistogramWhitelistName[] = "whitelist";
42
43 const char kPopularSitesFieldTrialName[] = "NTPPopularSites";
44
45 // The visual type of a most visited tile.
46 //
47 // These values must stay in sync with the MostVisitedTileType enum
48 // in histograms.xml.
49 //
50 // A Java counterpart will be generated for this enum.
51 // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.ntp
52 enum MostVisitedTileType {
53 // The icon or thumbnail hasn't loaded yet.
54 NONE,
55 // The item displays a site's actual favicon or touch icon.
56 ICON_REAL,
57 // The item displays a color derived from the site's favicon or touch icon.
58 ICON_COLOR,
59 // The item displays a default gray box in place of an icon.
60 ICON_DEFAULT,
61 NUM_TILE_TYPES,
62 };
63
64 // May only be called from blocking thread pool.
65 std::unique_ptr<SkBitmap> MaybeFetchLocalThumbnail(
66 const GURL& url,
67 const scoped_refptr<TopSites>& top_sites) {
68 scoped_refptr<base::RefCountedMemory> image;
69 std::unique_ptr<SkBitmap> bitmap;
70 if (top_sites && top_sites->GetPageThumbnail(url, false, &image))
71 bitmap = gfx::JPEGCodec::Decode(image->front(), image->size());
72 return bitmap;
73 }
74
75 // Log an event for a given |histogram| at a given element |position|. This
76 // routine exists because regular histogram macros are cached thus can't be used
77 // if the name of the histogram will change at a given call site.
78 void LogHistogramEvent(const std::string& histogram,
79 int position,
80 int num_sites) {
81 base::HistogramBase* counter = base::LinearHistogram::FactoryGet(
82 histogram,
83 1,
84 num_sites,
85 num_sites + 1,
86 base::Histogram::kUmaTargetedHistogramFlag);
87 if (counter)
88 counter->Add(position);
89 }
90
91 bool ShouldShowPopularSites() {
92 // Note: It's important to query the field trial state first, to ensure that
93 // UMA reports the correct group.
94 const std::string group_name =
95 base::FieldTrialList::FindFullName(kPopularSitesFieldTrialName);
96 base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
97 if (cmd_line->HasSwitch(ntp_tiles::switches::kDisableNTPPopularSites))
98 return false;
99 if (cmd_line->HasSwitch(ntp_tiles::switches::kEnableNTPPopularSites))
100 return true;
101 return base::StartsWith(group_name, "Enabled",
102 base::CompareCase::INSENSITIVE_ASCII);
103 }
104
105 std::string GetPopularSitesCountry() {
106 return variations::GetVariationParamValue(kPopularSitesFieldTrialName,
107 "country");
108 }
109
110 std::string GetPopularSitesVersion() {
111 return variations::GetVariationParamValue(kPopularSitesFieldTrialName,
112 "version");
113 }
114
115 // Determine whether we need any popular suggestions to fill up a grid of
116 // |num_tiles| tiles.
117 bool NeedPopularSites(const PrefService* prefs, size_t num_tiles) {
118 const base::ListValue* source_list =
119 prefs->GetList(ntp_tiles::prefs::kNTPSuggestionsIsPersonal);
120 // If there aren't enough previous suggestions to fill the grid, we need
121 // popular suggestions.
122 if (source_list->GetSize() < num_tiles)
123 return true;
124 // Otherwise, if any of the previous suggestions is not personal, then also
125 // get popular suggestions.
126 for (size_t i = 0; i < num_tiles; ++i) {
127 bool is_personal = false;
128 if (source_list->GetBoolean(i, &is_personal) && !is_personal)
129 return true;
130 }
131 // The whole grid is already filled with personal suggestions, no point in
132 // bothering with popular ones.
133 return false;
134 }
135
136 bool AreURLsEquivalent(const GURL& url1, const GURL& url2) {
137 return url1.host() == url2.host() && url1.path() == url2.path();
138 }
139
140 std::string GetSourceHistogramName(
141 const MostVisitedSites::Suggestion& suggestion) {
142 switch (suggestion.source) {
143 case MostVisitedSites::TOP_SITES:
144 return kHistogramClientName;
145 case MostVisitedSites::POPULAR:
146 return kHistogramPopularName;
147 case MostVisitedSites::WHITELIST:
148 return kHistogramWhitelistName;
149 case MostVisitedSites::SUGGESTIONS_SERVICE:
150 return suggestion.provider_index >= 0
151 ? base::StringPrintf(kHistogramServerFormat,
152 suggestion.provider_index)
153 : kHistogramServerName;
154 }
155 NOTREACHED();
156 return std::string();
157 }
158
159 } // namespace
160
161 MostVisitedSites::Suggestion::Suggestion() : provider_index(-1) {}
162
163 MostVisitedSites::Suggestion::~Suggestion() {}
164
165 MostVisitedSites::Suggestion::Suggestion(Suggestion&&) = default;
166 MostVisitedSites::Suggestion&
167 MostVisitedSites::Suggestion::operator=(Suggestion&&) = default;
168
169 MostVisitedSites::MostVisitedSites(
170 scoped_refptr<base::SequencedWorkerPool> blocking_pool,
171 PrefService* prefs,
172 const TemplateURLService* template_url_service,
173 variations::VariationsService* variations_service,
174 net::URLRequestContextGetter* download_context,
175 const base::FilePath& popular_sites_directory,
176 scoped_refptr<history::TopSites> top_sites,
177 SuggestionsService* suggestions,
178 MostVisitedSitesSupervisor* supervisor)
179 : prefs_(prefs),
180 template_url_service_(template_url_service),
181 variations_service_(variations_service),
182 download_context_(download_context),
183 popular_sites_directory_(popular_sites_directory),
184 top_sites_(top_sites),
185 suggestions_service_(suggestions),
186 supervisor_(supervisor),
187 observer_(nullptr),
188 num_sites_(0),
189 received_most_visited_sites_(false),
190 received_popular_sites_(false),
191 recorded_uma_(false),
192 scoped_observer_(this),
193 mv_source_(SUGGESTIONS_SERVICE),
194 blocking_pool_(std::move(blocking_pool)),
195 blocking_runner_(blocking_pool_->GetTaskRunnerWithShutdownBehavior(
196 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)),
197 weak_ptr_factory_(this) {
198 supervisor_->SetObserver(this);
199 }
200
201 MostVisitedSites::~MostVisitedSites() {
202 supervisor_->SetObserver(nullptr);
203 }
204
205 void MostVisitedSites::SetMostVisitedURLsObserver(Observer* observer,
206 int num_sites) {
207 DCHECK(observer);
208 observer_ = observer;
209 num_sites_ = num_sites;
210
211 if (ShouldShowPopularSites() &&
212 NeedPopularSites(prefs_, num_sites_)) {
213 popular_sites_.reset(new PopularSites(
214 blocking_pool_, prefs_, template_url_service_, variations_service_,
215 download_context_, popular_sites_directory_, GetPopularSitesCountry(),
216 GetPopularSitesVersion(), false,
217 base::Bind(&MostVisitedSites::OnPopularSitesAvailable,
218 base::Unretained(this))));
219 } else {
220 received_popular_sites_ = true;
221 }
222
223 // TODO(treib): Can |top_sites_| ever be null? If not, remove these checks.
224 if (top_sites_) {
225 // TopSites updates itself after a delay. To ensure up-to-date results,
226 // force an update now.
227 top_sites_->SyncWithHistory();
228
229 // Register as TopSitesObserver so that we can update ourselves when the
230 // TopSites changes.
231 scoped_observer_.Add(top_sites_.get());
232 }
233
234 suggestions_subscription_ = suggestions_service_->AddCallback(
235 base::Bind(&MostVisitedSites::OnSuggestionsProfileAvailable,
236 base::Unretained(this)));
237
238 // Immediately build the current suggestions, getting personal suggestions
239 // from the SuggestionsService's cache or, if that is empty, from TopSites.
240 BuildCurrentSuggestions();
241 // Also start a request for fresh suggestions.
242 suggestions_service_->FetchSuggestionsData();
243 }
244
245 void MostVisitedSites::GetURLThumbnail(const GURL& url,
246 const ThumbnailCallback& callback) {
247 DCHECK(thread_checker_.CalledOnValidThread());
248
249 base::PostTaskAndReplyWithResult(
250 blocking_runner_.get(), FROM_HERE,
251 base::Bind(&MaybeFetchLocalThumbnail, url, top_sites_),
252 base::Bind(&MostVisitedSites::OnLocalThumbnailFetched,
253 weak_ptr_factory_.GetWeakPtr(), url, callback));
254 }
255
256 void MostVisitedSites::OnLocalThumbnailFetched(
257 const GURL& url,
258 const ThumbnailCallback& callback,
259 std::unique_ptr<SkBitmap> bitmap) {
260 DCHECK(thread_checker_.CalledOnValidThread());
261 if (bitmap.get()) {
262 callback.Run(true /* is_local_thumbnail */, bitmap.get());
263 return;
264 }
265
266 // A thumbnail is not locally available for |url|. Make sure it is put in
267 // the list to be fetched at the next visit to this site.
268 if (top_sites_)
269 top_sites_->AddForcedURL(url, base::Time::Now());
270 // Also fetch a remote thumbnail if possible. PopularSites or the
271 // SuggestionsService can supply a thumbnail download URL.
272 if (popular_sites_) {
273 const std::vector<PopularSites::Site>& sites = popular_sites_->sites();
274 auto it = std::find_if(
275 sites.begin(), sites.end(),
276 [&url](const PopularSites::Site& site) { return site.url == url; });
277 if (it != sites.end() && it->thumbnail_url.is_valid()) {
278 return suggestions_service_->GetPageThumbnailWithURL(
279 url, it->thumbnail_url,
280 base::Bind(&MostVisitedSites::OnObtainedThumbnail,
281 weak_ptr_factory_.GetWeakPtr(), false, callback));
282 }
283 }
284 if (mv_source_ == SUGGESTIONS_SERVICE) {
285 return suggestions_service_->GetPageThumbnail(
286 url, base::Bind(&MostVisitedSites::OnObtainedThumbnail,
287 weak_ptr_factory_.GetWeakPtr(), false, callback));
288 }
289 // If no bitmap could be fetched and neither PopularSites nor the
290 // SuggestionsService is available then a nullptr is passed to the callback.
291 callback.Run(true /* is_local_thumbnail */, nullptr);
292 }
293
294 void MostVisitedSites::OnObtainedThumbnail(bool is_local_thumbnail,
295 const ThumbnailCallback& callback,
296 const GURL& url,
297 const gfx::Image& image) {
298 DCHECK(thread_checker_.CalledOnValidThread());
299 const SkBitmap* bitmap = nullptr;
300 if (!image.IsEmpty())
301 bitmap = image.ToSkBitmap();
302 callback.Run(is_local_thumbnail, bitmap);
303 }
304
305 void MostVisitedSites::AddOrRemoveBlacklistedUrl(const GURL& url,
306 bool add_url) {
307 // Always blacklist in the local TopSites.
308 if (top_sites_) {
309 if (add_url)
310 top_sites_->AddBlacklistedURL(url);
311 else
312 top_sites_->RemoveBlacklistedURL(url);
313 }
314
315 // Only blacklist in the server-side suggestions service if it's active.
316 if (mv_source_ == SUGGESTIONS_SERVICE) {
317 if (add_url)
318 suggestions_service_->BlacklistURL(url);
319 else
320 suggestions_service_->UndoBlacklistURL(url);
321 }
322 }
323
324 void MostVisitedSites::RecordTileTypeMetrics(
325 const std::vector<int>& tile_types) {
326 DCHECK_EQ(current_suggestions_.size(), tile_types.size());
327 int counts_per_type[NUM_TILE_TYPES] = {0};
328 for (size_t i = 0; i < tile_types.size(); ++i) {
329 int tile_type = tile_types[i];
330 ++counts_per_type[tile_type];
331 std::string histogram = base::StringPrintf(
332 "NewTabPage.TileType.%s",
333 GetSourceHistogramName(current_suggestions_[i]).c_str());
334 LogHistogramEvent(histogram, tile_type, NUM_TILE_TYPES);
335 }
336
337 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.IconsReal",
338 counts_per_type[ICON_REAL]);
339 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.IconsColor",
340 counts_per_type[ICON_COLOR]);
341 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.IconsGray",
342 counts_per_type[ICON_DEFAULT]);
343 }
344
345 void MostVisitedSites::RecordOpenedMostVisitedItem(int index, int tile_type) {
346 DCHECK_GE(index, 0);
347 DCHECK_LT(index, static_cast<int>(current_suggestions_.size()));
348 std::string histogram = base::StringPrintf(
349 "NewTabPage.MostVisited.%s",
350 GetSourceHistogramName(current_suggestions_[index]).c_str());
351 LogHistogramEvent(histogram, index, num_sites_);
352
353 histogram = base::StringPrintf(
354 "NewTabPage.TileTypeClicked.%s",
355 GetSourceHistogramName(current_suggestions_[index]).c_str());
356 LogHistogramEvent(histogram, tile_type, NUM_TILE_TYPES);
357 }
358
359 void MostVisitedSites::OnBlockedSitesChanged() {
360 BuildCurrentSuggestions();
361 }
362
363 // static
364 void MostVisitedSites::RegisterProfilePrefs(
365 user_prefs::PrefRegistrySyncable* registry) {
366 // TODO(treib): Remove this, it's unused. Do we need migration code to clean
367 // up existing entries?
368 registry->RegisterListPref(ntp_tiles::prefs::kNTPSuggestionsURL);
369 // TODO(treib): Remove this. It's only used to determine if we need
370 // PopularSites at all. Find a way to do that without prefs, or failing that,
371 // replace this list pref by a simple bool.
372 registry->RegisterListPref(ntp_tiles::prefs::kNTPSuggestionsIsPersonal);
373 }
374
375 void MostVisitedSites::BuildCurrentSuggestions() {
376 // Get the current suggestions from cache. If the cache is empty, this will
377 // fall back to TopSites.
378 OnSuggestionsProfileAvailable(
379 suggestions_service_->GetSuggestionsDataFromCache());
380 }
381
382 void MostVisitedSites::InitiateTopSitesQuery() {
383 if (!top_sites_)
384 return;
385
386 top_sites_->GetMostVisitedURLs(
387 base::Bind(&MostVisitedSites::OnMostVisitedURLsAvailable,
388 weak_ptr_factory_.GetWeakPtr()),
389 false);
390 }
391
392 base::FilePath MostVisitedSites::GetWhitelistLargeIconPath(const GURL& url) {
393 for (const auto& whitelist : supervisor_->whitelists()) {
394 if (AreURLsEquivalent(whitelist.entry_point, url))
395 return whitelist.large_icon_path;
396 }
397 return base::FilePath();
398 }
399
400 void MostVisitedSites::OnMostVisitedURLsAvailable(
401 const history::MostVisitedURLList& visited_list) {
402 SuggestionsPtrVector suggestions;
403 size_t num_tiles =
404 std::min(visited_list.size(), static_cast<size_t>(num_sites_));
405 for (size_t i = 0; i < num_tiles; ++i) {
406 const history::MostVisitedURL& visited = visited_list[i];
407 if (visited.url.is_empty()) {
408 num_tiles = i;
409 break; // This is the signal that there are no more real visited sites.
410 }
411 if (supervisor_->IsBlocked(visited.url))
412 continue;
413
414 std::unique_ptr<Suggestion> suggestion(new Suggestion());
415 suggestion->title = visited.title;
416 suggestion->url = visited.url;
417 suggestion->source = TOP_SITES;
418 suggestion->whitelist_icon_path = GetWhitelistLargeIconPath(visited.url);
419
420 suggestions.push_back(std::move(suggestion));
421 }
422
423 received_most_visited_sites_ = true;
424 mv_source_ = TOP_SITES;
425 SaveNewSuggestions(&suggestions);
426 NotifyMostVisitedURLsObserver();
427 }
428
429 void MostVisitedSites::OnSuggestionsProfileAvailable(
430 const SuggestionsProfile& suggestions_profile) {
431 int num_tiles = suggestions_profile.suggestions_size();
432 // With no server suggestions, fall back to local TopSites.
433 if (num_tiles == 0) {
434 InitiateTopSitesQuery();
435 return;
436 }
437 if (num_sites_ < num_tiles)
438 num_tiles = num_sites_;
439
440 SuggestionsPtrVector suggestions;
441 for (int i = 0; i < num_tiles; ++i) {
442 const ChromeSuggestion& suggestion = suggestions_profile.suggestions(i);
443 if (supervisor_->IsBlocked(GURL(suggestion.url())))
444 continue;
445
446 std::unique_ptr<Suggestion> generated_suggestion(new Suggestion());
447 generated_suggestion->title = base::UTF8ToUTF16(suggestion.title());
448 generated_suggestion->url = GURL(suggestion.url());
449 generated_suggestion->source = SUGGESTIONS_SERVICE;
450 generated_suggestion->whitelist_icon_path = GetWhitelistLargeIconPath(
451 GURL(suggestion.url()));
452 if (suggestion.providers_size() > 0)
453 generated_suggestion->provider_index = suggestion.providers(0);
454
455 suggestions.push_back(std::move(generated_suggestion));
456 }
457
458 received_most_visited_sites_ = true;
459 mv_source_ = SUGGESTIONS_SERVICE;
460 SaveNewSuggestions(&suggestions);
461 NotifyMostVisitedURLsObserver();
462 }
463
464 MostVisitedSites::SuggestionsPtrVector
465 MostVisitedSites::CreateWhitelistEntryPointSuggestions(
466 const SuggestionsPtrVector& personal_suggestions) {
467 size_t num_personal_suggestions = personal_suggestions.size();
468 DCHECK_LE(num_personal_suggestions, static_cast<size_t>(num_sites_));
469
470 size_t num_whitelist_suggestions = num_sites_ - num_personal_suggestions;
471 SuggestionsPtrVector whitelist_suggestions;
472
473 std::set<std::string> personal_hosts;
474 for (const auto& suggestion : personal_suggestions)
475 personal_hosts.insert(suggestion->url.host());
476
477 for (const auto& whitelist : supervisor_->whitelists()) {
478 // Skip blacklisted sites.
479 if (top_sites_ && top_sites_->IsBlacklisted(whitelist.entry_point))
480 continue;
481
482 // Skip suggestions already present.
483 if (personal_hosts.find(whitelist.entry_point.host()) !=
484 personal_hosts.end())
485 continue;
486
487 // Skip whitelist entry points that are manually blocked.
488 if (supervisor_->IsBlocked(whitelist.entry_point))
489 continue;
490
491 std::unique_ptr<Suggestion> suggestion(new Suggestion());
492 suggestion->title = whitelist.title;
493 suggestion->url = whitelist.entry_point;
494 suggestion->source = WHITELIST;
495 suggestion->whitelist_icon_path = whitelist.large_icon_path;
496
497 whitelist_suggestions.push_back(std::move(suggestion));
498 if (whitelist_suggestions.size() >= num_whitelist_suggestions)
499 break;
500 }
501
502 return whitelist_suggestions;
503 }
504
505 MostVisitedSites::SuggestionsPtrVector
506 MostVisitedSites::CreatePopularSitesSuggestions(
507 const SuggestionsPtrVector& personal_suggestions,
508 const SuggestionsPtrVector& whitelist_suggestions) {
509 // For child accounts popular sites suggestions will not be added.
510 if (supervisor_->IsChildProfile())
511 return SuggestionsPtrVector();
512
513 size_t num_suggestions =
514 personal_suggestions.size() + whitelist_suggestions.size();
515 DCHECK_LE(num_suggestions, static_cast<size_t>(num_sites_));
516
517 // Collect non-blacklisted popular suggestions, skipping those already present
518 // in the personal suggestions.
519 size_t num_popular_sites_suggestions = num_sites_ - num_suggestions;
520 SuggestionsPtrVector popular_sites_suggestions;
521
522 if (num_popular_sites_suggestions > 0 && popular_sites_) {
523 std::set<std::string> hosts;
524 for (const auto& suggestion : personal_suggestions)
525 hosts.insert(suggestion->url.host());
526 for (const auto& suggestion : whitelist_suggestions)
527 hosts.insert(suggestion->url.host());
528 for (const PopularSites::Site& popular_site : popular_sites_->sites()) {
529 // Skip blacklisted sites.
530 if (top_sites_ && top_sites_->IsBlacklisted(popular_site.url))
531 continue;
532 std::string host = popular_site.url.host();
533 // Skip suggestions already present in personal or whitelists.
534 if (hosts.find(host) != hosts.end())
535 continue;
536
537 std::unique_ptr<Suggestion> suggestion(new Suggestion());
538 suggestion->title = popular_site.title;
539 suggestion->url = GURL(popular_site.url);
540 suggestion->source = POPULAR;
541
542 popular_sites_suggestions.push_back(std::move(suggestion));
543 if (popular_sites_suggestions.size() >= num_popular_sites_suggestions)
544 break;
545 }
546 }
547 return popular_sites_suggestions;
548 }
549
550 void MostVisitedSites::SaveNewSuggestions(
551 SuggestionsPtrVector* personal_suggestions) {
552 SuggestionsPtrVector whitelist_suggestions =
553 CreateWhitelistEntryPointSuggestions(*personal_suggestions);
554 SuggestionsPtrVector popular_sites_suggestions =
555 CreatePopularSitesSuggestions(*personal_suggestions,
556 whitelist_suggestions);
557
558 size_t num_actual_tiles = personal_suggestions->size() +
559 whitelist_suggestions.size() +
560 popular_sites_suggestions.size();
561 DCHECK_LE(num_actual_tiles, static_cast<size_t>(num_sites_));
562
563 SuggestionsPtrVector merged_suggestions = MergeSuggestions(
564 personal_suggestions, &whitelist_suggestions, &popular_sites_suggestions);
565 DCHECK_EQ(num_actual_tiles, merged_suggestions.size());
566
567 current_suggestions_.resize(merged_suggestions.size());
568 for (size_t i = 0; i < merged_suggestions.size(); ++i)
569 std::swap(*merged_suggestions[i], current_suggestions_[i]);
570
571 if (received_popular_sites_)
572 SaveCurrentSuggestionsToPrefs();
573 }
574
575 // static
576 MostVisitedSites::SuggestionsPtrVector MostVisitedSites::MergeSuggestions(
577 SuggestionsPtrVector* personal_suggestions,
578 SuggestionsPtrVector* whitelist_suggestions,
579 SuggestionsPtrVector* popular_suggestions) {
580 size_t num_personal_suggestions = personal_suggestions->size();
581 size_t num_whitelist_suggestions = whitelist_suggestions->size();
582 size_t num_popular_suggestions = popular_suggestions->size();
583 size_t num_tiles = num_popular_suggestions + num_whitelist_suggestions +
584 num_personal_suggestions;
585 SuggestionsPtrVector merged_suggestions;
586 AppendSuggestions(personal_suggestions, &merged_suggestions);
587 AppendSuggestions(whitelist_suggestions, &merged_suggestions);
588 AppendSuggestions(popular_suggestions, &merged_suggestions);
589 DCHECK_EQ(num_tiles, merged_suggestions.size());
590
591 return merged_suggestions;
592 }
593
594 // TODO(treib): Once we use SuggestionsVector (non-Ptr) everywhere, move this
595 // into an anonymous namespace.
596 // static
597 void MostVisitedSites::AppendSuggestions(SuggestionsPtrVector* src,
598 SuggestionsPtrVector* dst) {
599 dst->insert(dst->end(),
600 std::make_move_iterator(src->begin()),
601 std::make_move_iterator(src->end()));
602 }
603
604 void MostVisitedSites::SaveCurrentSuggestionsToPrefs() {
605 base::ListValue url_list;
606 base::ListValue source_list;
607 for (const auto& suggestion : current_suggestions_) {
608 url_list.AppendString(suggestion.url.spec());
609 source_list.AppendBoolean(suggestion.source != POPULAR);
610 }
611 prefs_->Set(ntp_tiles::prefs::kNTPSuggestionsIsPersonal, source_list);
612 prefs_->Set(ntp_tiles::prefs::kNTPSuggestionsURL, url_list);
613 }
614
615 void MostVisitedSites::NotifyMostVisitedURLsObserver() {
616 if (received_most_visited_sites_ && received_popular_sites_ &&
617 !recorded_uma_) {
618 RecordImpressionUMAMetrics();
619 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.NumberOfTiles",
620 current_suggestions_.size());
621 recorded_uma_ = true;
622 }
623
624 if (!observer_)
625 return;
626
627 observer_->OnMostVisitedURLsAvailable(current_suggestions_);
628 }
629
630 void MostVisitedSites::OnPopularSitesAvailable(bool success) {
631 received_popular_sites_ = true;
632
633 if (!success) {
634 LOG(WARNING) << "Download of popular sites failed";
635 return;
636 }
637
638 // Pass the popular sites to the observer. This will cause it to fetch any
639 // missing icons, but will *not* cause it to display the popular sites.
640 observer_->OnPopularURLsAvailable(popular_sites_->sites());
641
642 // Re-build the suggestions list. Once done, this will notify the observer.
643 BuildCurrentSuggestions();
644 }
645
646 void MostVisitedSites::RecordImpressionUMAMetrics() {
647 for (size_t i = 0; i < current_suggestions_.size(); i++) {
648 std::string histogram = base::StringPrintf(
649 "NewTabPage.SuggestionsImpression.%s",
650 GetSourceHistogramName(current_suggestions_[i]).c_str());
651 LogHistogramEvent(histogram, static_cast<int>(i), num_sites_);
652 }
653 }
654
655 void MostVisitedSites::TopSitesLoaded(TopSites* top_sites) {}
656
657 void MostVisitedSites::TopSitesChanged(TopSites* top_sites,
658 ChangeReason change_reason) {
659 if (mv_source_ == TOP_SITES) {
660 // The displayed suggestions are invalidated.
661 InitiateTopSitesQuery();
662 }
663 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698