| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/android/ntp/most_visited_sites.h" | 5 #include "chrome/browser/android/ntp/most_visited_sites.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/callback.h" | 9 #include "base/callback.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 193 scoped_observer_(this), | 193 scoped_observer_(this), |
| 194 mv_source_(SUGGESTIONS_SERVICE), | 194 mv_source_(SUGGESTIONS_SERVICE), |
| 195 weak_ptr_factory_(this) { | 195 weak_ptr_factory_(this) { |
| 196 supervisor_->SetObserver(this); | 196 supervisor_->SetObserver(this); |
| 197 } | 197 } |
| 198 | 198 |
| 199 MostVisitedSites::~MostVisitedSites() { | 199 MostVisitedSites::~MostVisitedSites() { |
| 200 supervisor_->SetObserver(nullptr); | 200 supervisor_->SetObserver(nullptr); |
| 201 } | 201 } |
| 202 | 202 |
| 203 void MostVisitedSites::SetMostVisitedURLsObserver( | 203 void MostVisitedSites::SetMostVisitedURLsObserver(Observer* observer, |
| 204 MostVisitedSites::Observer* observer, int num_sites) { | 204 int num_sites) { |
| 205 DCHECK(observer); | 205 DCHECK(observer); |
| 206 observer_ = observer; | 206 observer_ = observer; |
| 207 num_sites_ = num_sites; | 207 num_sites_ = num_sites; |
| 208 | 208 |
| 209 if (ShouldShowPopularSites() && | 209 if (ShouldShowPopularSites() && |
| 210 NeedPopularSites(prefs_, num_sites_)) { | 210 NeedPopularSites(prefs_, num_sites_)) { |
| 211 popular_sites_.reset(new PopularSites( | 211 popular_sites_.reset(new PopularSites( |
| 212 prefs_, template_url_service_, variations_service_, download_context_, | 212 prefs_, template_url_service_, variations_service_, download_context_, |
| 213 popular_sites_directory_, GetPopularSitesCountry(), | 213 popular_sites_directory_, GetPopularSitesCountry(), |
| 214 GetPopularSitesVersion(), false, | 214 GetPopularSitesVersion(), false, |
| 215 base::Bind(&MostVisitedSites::OnPopularSitesAvailable, | 215 base::Bind(&MostVisitedSites::OnPopularSitesAvailable, |
| 216 base::Unretained(this)))); | 216 base::Unretained(this)))); |
| 217 } else { | 217 } else { |
| 218 received_popular_sites_ = true; | 218 received_popular_sites_ = true; |
| 219 } | 219 } |
| 220 | 220 |
| 221 // TODO(treib): Can |top_sites_| ever be null? If not, remove these checks. |
| 221 if (top_sites_) { | 222 if (top_sites_) { |
| 222 // TopSites updates itself after a delay. To ensure up-to-date results, | 223 // TopSites updates itself after a delay. To ensure up-to-date results, |
| 223 // force an update now. | 224 // force an update now. |
| 224 top_sites_->SyncWithHistory(); | 225 top_sites_->SyncWithHistory(); |
| 225 | 226 |
| 226 // Register as TopSitesObserver so that we can update ourselves when the | 227 // Register as TopSitesObserver so that we can update ourselves when the |
| 227 // TopSites changes. | 228 // TopSites changes. |
| 228 scoped_observer_.Add(top_sites_.get()); | 229 scoped_observer_.Add(top_sites_.get()); |
| 229 } | 230 } |
| 230 | 231 |
| 231 suggestions_subscription_ = suggestions_service_->AddCallback( | 232 suggestions_subscription_ = suggestions_service_->AddCallback( |
| 232 base::Bind(&MostVisitedSites::OnSuggestionsProfileAvailable, | 233 base::Bind(&MostVisitedSites::OnSuggestionsProfileAvailable, |
| 233 base::Unretained(this))); | 234 base::Unretained(this))); |
| 234 | 235 |
| 235 // Immediately build the current suggestions, getting personal suggestions | 236 // Immediately build the current suggestions, getting personal suggestions |
| 236 // from the SuggestionsService's cache or, if that is empty, from TopSites. | 237 // from the SuggestionsService's cache or, if that is empty, from TopSites. |
| 237 BuildCurrentSuggestions(); | 238 BuildCurrentSuggestions(); |
| 238 // Also start a request for fresh suggestions. | 239 // Also start a request for fresh suggestions. |
| 239 suggestions_service_->FetchSuggestionsData(); | 240 suggestions_service_->FetchSuggestionsData(); |
| 240 } | 241 } |
| 241 | 242 |
| 242 void MostVisitedSites::GetURLThumbnail( | 243 void MostVisitedSites::GetURLThumbnail(const GURL& url, |
| 243 const GURL& url, | 244 const ThumbnailCallback& callback) { |
| 244 const ThumbnailCallback& callback) { | |
| 245 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 245 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 246 | 246 |
| 247 // TODO(treib): Move this to the blocking pool? Doesn't seem related to DB. |
| 247 BrowserThread::PostTaskAndReplyWithResult( | 248 BrowserThread::PostTaskAndReplyWithResult( |
| 248 BrowserThread::DB, FROM_HERE, | 249 BrowserThread::DB, FROM_HERE, |
| 249 base::Bind(&MaybeFetchLocalThumbnail, url, top_sites_), | 250 base::Bind(&MaybeFetchLocalThumbnail, url, top_sites_), |
| 250 base::Bind(&MostVisitedSites::OnLocalThumbnailFetched, | 251 base::Bind(&MostVisitedSites::OnLocalThumbnailFetched, |
| 251 weak_ptr_factory_.GetWeakPtr(), url, callback)); | 252 weak_ptr_factory_.GetWeakPtr(), url, callback)); |
| 252 } | 253 } |
| 253 | 254 |
| 254 void MostVisitedSites::OnLocalThumbnailFetched( | 255 void MostVisitedSites::OnLocalThumbnailFetched( |
| 255 const GURL& url, | 256 const GURL& url, |
| 256 const ThumbnailCallback& callback, | 257 const ThumbnailCallback& callback, |
| (...skipping 20 matching lines...) Expand all Loading... |
| 277 } | 278 } |
| 278 if (mv_source_ == SUGGESTIONS_SERVICE) { | 279 if (mv_source_ == SUGGESTIONS_SERVICE) { |
| 279 return suggestions_service_->GetPageThumbnail( | 280 return suggestions_service_->GetPageThumbnail( |
| 280 url, base::Bind(&MostVisitedSites::OnObtainedThumbnail, | 281 url, base::Bind(&MostVisitedSites::OnObtainedThumbnail, |
| 281 weak_ptr_factory_.GetWeakPtr(), false, callback)); | 282 weak_ptr_factory_.GetWeakPtr(), false, callback)); |
| 282 } | 283 } |
| 283 } | 284 } |
| 284 OnObtainedThumbnail(true, callback, url, bitmap.get()); | 285 OnObtainedThumbnail(true, callback, url, bitmap.get()); |
| 285 } | 286 } |
| 286 | 287 |
| 287 void MostVisitedSites::OnObtainedThumbnail( | 288 void MostVisitedSites::OnObtainedThumbnail(bool is_local_thumbnail, |
| 288 bool is_local_thumbnail, | 289 const ThumbnailCallback& callback, |
| 289 const ThumbnailCallback& callback, | 290 const GURL& url, |
| 290 const GURL& url, | 291 const SkBitmap* bitmap) { |
| 291 const SkBitmap* bitmap) { | |
| 292 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 292 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 293 callback.Run(is_local_thumbnail, bitmap); | 293 callback.Run(is_local_thumbnail, bitmap); |
| 294 } | 294 } |
| 295 | 295 |
| 296 void MostVisitedSites::AddOrRemoveBlacklistedUrl( | 296 void MostVisitedSites::AddOrRemoveBlacklistedUrl(const GURL& url, |
| 297 const GURL& url, bool add_url) { | 297 bool add_url) { |
| 298 // Always blacklist in the local TopSites. | 298 // Always blacklist in the local TopSites. |
| 299 if (top_sites_) { | 299 if (top_sites_) { |
| 300 if (add_url) | 300 if (add_url) |
| 301 top_sites_->AddBlacklistedURL(url); | 301 top_sites_->AddBlacklistedURL(url); |
| 302 else | 302 else |
| 303 top_sites_->RemoveBlacklistedURL(url); | 303 top_sites_->RemoveBlacklistedURL(url); |
| 304 } | 304 } |
| 305 | 305 |
| 306 // Only blacklist in the server-side suggestions service if it's active. | 306 // Only blacklist in the server-side suggestions service if it's active. |
| 307 if (mv_source_ == SUGGESTIONS_SERVICE) { | 307 if (mv_source_ == SUGGESTIONS_SERVICE) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 347 LogHistogramEvent(histogram, tile_type, NUM_TILE_TYPES); | 347 LogHistogramEvent(histogram, tile_type, NUM_TILE_TYPES); |
| 348 } | 348 } |
| 349 | 349 |
| 350 void MostVisitedSites::OnBlockedSitesChanged() { | 350 void MostVisitedSites::OnBlockedSitesChanged() { |
| 351 BuildCurrentSuggestions(); | 351 BuildCurrentSuggestions(); |
| 352 } | 352 } |
| 353 | 353 |
| 354 // static | 354 // static |
| 355 void MostVisitedSites::RegisterProfilePrefs( | 355 void MostVisitedSites::RegisterProfilePrefs( |
| 356 user_prefs::PrefRegistrySyncable* registry) { | 356 user_prefs::PrefRegistrySyncable* registry) { |
| 357 // TODO(treib): Remove this, it's unused. Do we need migration code to clean |
| 358 // up existing entries? |
| 357 registry->RegisterListPref(ntp_tiles::prefs::kNTPSuggestionsURL); | 359 registry->RegisterListPref(ntp_tiles::prefs::kNTPSuggestionsURL); |
| 360 // TODO(treib): Remove this. It's only used to determine if we need |
| 361 // PopularSites at all. Find a way to do that without prefs, or failing that, |
| 362 // replace this list pref by a simple bool. |
| 358 registry->RegisterListPref(ntp_tiles::prefs::kNTPSuggestionsIsPersonal); | 363 registry->RegisterListPref(ntp_tiles::prefs::kNTPSuggestionsIsPersonal); |
| 359 } | 364 } |
| 360 | 365 |
| 361 void MostVisitedSites::BuildCurrentSuggestions() { | 366 void MostVisitedSites::BuildCurrentSuggestions() { |
| 362 // Get the current suggestions from cache. If the cache is empty, this will | 367 // Get the current suggestions from cache. If the cache is empty, this will |
| 363 // fall back to TopSites. | 368 // fall back to TopSites. |
| 364 OnSuggestionsProfileAvailable( | 369 OnSuggestionsProfileAvailable( |
| 365 suggestions_service_->GetSuggestionsDataFromCache()); | 370 suggestions_service_->GetSuggestionsDataFromCache()); |
| 366 } | 371 } |
| 367 | 372 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 378 base::FilePath MostVisitedSites::GetWhitelistLargeIconPath(const GURL& url) { | 383 base::FilePath MostVisitedSites::GetWhitelistLargeIconPath(const GURL& url) { |
| 379 for (const auto& whitelist : supervisor_->whitelists()) { | 384 for (const auto& whitelist : supervisor_->whitelists()) { |
| 380 if (AreURLsEquivalent(whitelist.entry_point, url)) | 385 if (AreURLsEquivalent(whitelist.entry_point, url)) |
| 381 return whitelist.large_icon_path; | 386 return whitelist.large_icon_path; |
| 382 } | 387 } |
| 383 return base::FilePath(); | 388 return base::FilePath(); |
| 384 } | 389 } |
| 385 | 390 |
| 386 void MostVisitedSites::OnMostVisitedURLsAvailable( | 391 void MostVisitedSites::OnMostVisitedURLsAvailable( |
| 387 const history::MostVisitedURLList& visited_list) { | 392 const history::MostVisitedURLList& visited_list) { |
| 388 MostVisitedSites::SuggestionsPtrVector suggestions; | 393 SuggestionsPtrVector suggestions; |
| 389 size_t num_tiles = | 394 size_t num_tiles = |
| 390 std::min(visited_list.size(), static_cast<size_t>(num_sites_)); | 395 std::min(visited_list.size(), static_cast<size_t>(num_sites_)); |
| 391 for (size_t i = 0; i < num_tiles; ++i) { | 396 for (size_t i = 0; i < num_tiles; ++i) { |
| 392 const history::MostVisitedURL& visited = visited_list[i]; | 397 const history::MostVisitedURL& visited = visited_list[i]; |
| 393 if (visited.url.is_empty()) { | 398 if (visited.url.is_empty()) { |
| 394 num_tiles = i; | 399 num_tiles = i; |
| 395 break; // This is the signal that there are no more real visited sites. | 400 break; // This is the signal that there are no more real visited sites. |
| 396 } | 401 } |
| 397 if (supervisor_->IsBlocked(visited.url)) | 402 if (supervisor_->IsBlocked(visited.url)) |
| 398 continue; | 403 continue; |
| 399 | 404 |
| 400 std::unique_ptr<Suggestion> suggestion(new Suggestion()); | 405 std::unique_ptr<Suggestion> suggestion(new Suggestion()); |
| 401 suggestion->title = visited.title; | 406 suggestion->title = visited.title; |
| 402 suggestion->url = visited.url; | 407 suggestion->url = visited.url; |
| 403 suggestion->source = TOP_SITES; | 408 suggestion->source = TOP_SITES; |
| 404 suggestion->whitelist_icon_path = GetWhitelistLargeIconPath(visited.url); | 409 suggestion->whitelist_icon_path = GetWhitelistLargeIconPath(visited.url); |
| 405 | 410 |
| 406 suggestions.push_back(std::move(suggestion)); | 411 suggestions.push_back(std::move(suggestion)); |
| 407 } | 412 } |
| 408 | 413 |
| 409 received_most_visited_sites_ = true; | 414 received_most_visited_sites_ = true; |
| 410 mv_source_ = TOP_SITES; | 415 mv_source_ = TOP_SITES; |
| 411 SaveNewNTPSuggestions(&suggestions); | 416 SaveNewSuggestions(&suggestions); |
| 412 NotifyMostVisitedURLsObserver(); | 417 NotifyMostVisitedURLsObserver(); |
| 413 } | 418 } |
| 414 | 419 |
| 415 void MostVisitedSites::OnSuggestionsProfileAvailable( | 420 void MostVisitedSites::OnSuggestionsProfileAvailable( |
| 416 const SuggestionsProfile& suggestions_profile) { | 421 const SuggestionsProfile& suggestions_profile) { |
| 417 int num_tiles = suggestions_profile.suggestions_size(); | 422 int num_tiles = suggestions_profile.suggestions_size(); |
| 418 // With no server suggestions, fall back to local TopSites. | 423 // With no server suggestions, fall back to local TopSites. |
| 419 if (num_tiles == 0) { | 424 if (num_tiles == 0) { |
| 420 InitiateTopSitesQuery(); | 425 InitiateTopSitesQuery(); |
| 421 return; | 426 return; |
| 422 } | 427 } |
| 423 if (num_sites_ < num_tiles) | 428 if (num_sites_ < num_tiles) |
| 424 num_tiles = num_sites_; | 429 num_tiles = num_sites_; |
| 425 | 430 |
| 426 MostVisitedSites::SuggestionsPtrVector suggestions; | 431 SuggestionsPtrVector suggestions; |
| 427 for (int i = 0; i < num_tiles; ++i) { | 432 for (int i = 0; i < num_tiles; ++i) { |
| 428 const ChromeSuggestion& suggestion = suggestions_profile.suggestions(i); | 433 const ChromeSuggestion& suggestion = suggestions_profile.suggestions(i); |
| 429 if (supervisor_->IsBlocked(GURL(suggestion.url()))) | 434 if (supervisor_->IsBlocked(GURL(suggestion.url()))) |
| 430 continue; | 435 continue; |
| 431 | 436 |
| 432 std::unique_ptr<Suggestion> generated_suggestion(new Suggestion()); | 437 std::unique_ptr<Suggestion> generated_suggestion(new Suggestion()); |
| 433 generated_suggestion->title = base::UTF8ToUTF16(suggestion.title()); | 438 generated_suggestion->title = base::UTF8ToUTF16(suggestion.title()); |
| 434 generated_suggestion->url = GURL(suggestion.url()); | 439 generated_suggestion->url = GURL(suggestion.url()); |
| 435 generated_suggestion->source = SUGGESTIONS_SERVICE; | 440 generated_suggestion->source = SUGGESTIONS_SERVICE; |
| 436 generated_suggestion->whitelist_icon_path = GetWhitelistLargeIconPath( | 441 generated_suggestion->whitelist_icon_path = GetWhitelistLargeIconPath( |
| 437 GURL(suggestion.url())); | 442 GURL(suggestion.url())); |
| 438 if (suggestion.providers_size() > 0) | 443 if (suggestion.providers_size() > 0) |
| 439 generated_suggestion->provider_index = suggestion.providers(0); | 444 generated_suggestion->provider_index = suggestion.providers(0); |
| 440 | 445 |
| 441 suggestions.push_back(std::move(generated_suggestion)); | 446 suggestions.push_back(std::move(generated_suggestion)); |
| 442 } | 447 } |
| 443 | 448 |
| 444 received_most_visited_sites_ = true; | 449 received_most_visited_sites_ = true; |
| 445 mv_source_ = SUGGESTIONS_SERVICE; | 450 mv_source_ = SUGGESTIONS_SERVICE; |
| 446 SaveNewNTPSuggestions(&suggestions); | 451 SaveNewSuggestions(&suggestions); |
| 447 NotifyMostVisitedURLsObserver(); | 452 NotifyMostVisitedURLsObserver(); |
| 448 } | 453 } |
| 449 | 454 |
| 450 MostVisitedSites::SuggestionsPtrVector | 455 MostVisitedSites::SuggestionsPtrVector |
| 451 MostVisitedSites::CreateWhitelistEntryPointSuggestions( | 456 MostVisitedSites::CreateWhitelistEntryPointSuggestions( |
| 452 const MostVisitedSites::SuggestionsPtrVector& personal_suggestions) { | 457 const SuggestionsPtrVector& personal_suggestions) { |
| 453 size_t num_personal_suggestions = personal_suggestions.size(); | 458 size_t num_personal_suggestions = personal_suggestions.size(); |
| 454 DCHECK_LE(num_personal_suggestions, static_cast<size_t>(num_sites_)); | 459 DCHECK_LE(num_personal_suggestions, static_cast<size_t>(num_sites_)); |
| 455 | 460 |
| 456 size_t num_whitelist_suggestions = num_sites_ - num_personal_suggestions; | 461 size_t num_whitelist_suggestions = num_sites_ - num_personal_suggestions; |
| 457 MostVisitedSites::SuggestionsPtrVector whitelist_suggestions; | 462 SuggestionsPtrVector whitelist_suggestions; |
| 458 | 463 |
| 459 std::set<std::string> personal_hosts; | 464 std::set<std::string> personal_hosts; |
| 460 for (const auto& suggestion : personal_suggestions) | 465 for (const auto& suggestion : personal_suggestions) |
| 461 personal_hosts.insert(suggestion->url.host()); | 466 personal_hosts.insert(suggestion->url.host()); |
| 462 | 467 |
| 463 for (const auto& whitelist : supervisor_->whitelists()) { | 468 for (const auto& whitelist : supervisor_->whitelists()) { |
| 464 // Skip blacklisted sites. | 469 // Skip blacklisted sites. |
| 465 if (top_sites_ && top_sites_->IsBlacklisted(whitelist.entry_point)) | 470 if (top_sites_ && top_sites_->IsBlacklisted(whitelist.entry_point)) |
| 466 continue; | 471 continue; |
| 467 | 472 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 483 whitelist_suggestions.push_back(std::move(suggestion)); | 488 whitelist_suggestions.push_back(std::move(suggestion)); |
| 484 if (whitelist_suggestions.size() >= num_whitelist_suggestions) | 489 if (whitelist_suggestions.size() >= num_whitelist_suggestions) |
| 485 break; | 490 break; |
| 486 } | 491 } |
| 487 | 492 |
| 488 return whitelist_suggestions; | 493 return whitelist_suggestions; |
| 489 } | 494 } |
| 490 | 495 |
| 491 MostVisitedSites::SuggestionsPtrVector | 496 MostVisitedSites::SuggestionsPtrVector |
| 492 MostVisitedSites::CreatePopularSitesSuggestions( | 497 MostVisitedSites::CreatePopularSitesSuggestions( |
| 493 const MostVisitedSites::SuggestionsPtrVector& personal_suggestions, | 498 const SuggestionsPtrVector& personal_suggestions, |
| 494 const MostVisitedSites::SuggestionsPtrVector& whitelist_suggestions) { | 499 const SuggestionsPtrVector& whitelist_suggestions) { |
| 495 // For child accounts popular sites suggestions will not be added. | 500 // For child accounts popular sites suggestions will not be added. |
| 496 if (supervisor_->IsChildProfile()) | 501 if (supervisor_->IsChildProfile()) |
| 497 return MostVisitedSites::SuggestionsPtrVector(); | 502 return SuggestionsPtrVector(); |
| 498 | 503 |
| 499 size_t num_suggestions = | 504 size_t num_suggestions = |
| 500 personal_suggestions.size() + whitelist_suggestions.size(); | 505 personal_suggestions.size() + whitelist_suggestions.size(); |
| 501 DCHECK_LE(num_suggestions, static_cast<size_t>(num_sites_)); | 506 DCHECK_LE(num_suggestions, static_cast<size_t>(num_sites_)); |
| 502 | 507 |
| 503 // Collect non-blacklisted popular suggestions, skipping those already present | 508 // Collect non-blacklisted popular suggestions, skipping those already present |
| 504 // in the personal suggestions. | 509 // in the personal suggestions. |
| 505 size_t num_popular_sites_suggestions = num_sites_ - num_suggestions; | 510 size_t num_popular_sites_suggestions = num_sites_ - num_suggestions; |
| 506 MostVisitedSites::SuggestionsPtrVector popular_sites_suggestions; | 511 SuggestionsPtrVector popular_sites_suggestions; |
| 507 | 512 |
| 508 if (num_popular_sites_suggestions > 0 && popular_sites_) { | 513 if (num_popular_sites_suggestions > 0 && popular_sites_) { |
| 509 std::set<std::string> hosts; | 514 std::set<std::string> hosts; |
| 510 for (const auto& suggestion : personal_suggestions) | 515 for (const auto& suggestion : personal_suggestions) |
| 511 hosts.insert(suggestion->url.host()); | 516 hosts.insert(suggestion->url.host()); |
| 512 for (const auto& suggestion : whitelist_suggestions) | 517 for (const auto& suggestion : whitelist_suggestions) |
| 513 hosts.insert(suggestion->url.host()); | 518 hosts.insert(suggestion->url.host()); |
| 514 for (const PopularSites::Site& popular_site : popular_sites_->sites()) { | 519 for (const PopularSites::Site& popular_site : popular_sites_->sites()) { |
| 515 // Skip blacklisted sites. | 520 // Skip blacklisted sites. |
| 516 if (top_sites_ && top_sites_->IsBlacklisted(popular_site.url)) | 521 if (top_sites_ && top_sites_->IsBlacklisted(popular_site.url)) |
| 517 continue; | 522 continue; |
| 518 std::string host = popular_site.url.host(); | 523 std::string host = popular_site.url.host(); |
| 519 // Skip suggestions already present in personal or whitelists. | 524 // Skip suggestions already present in personal or whitelists. |
| 520 if (hosts.find(host) != hosts.end()) | 525 if (hosts.find(host) != hosts.end()) |
| 521 continue; | 526 continue; |
| 522 | 527 |
| 523 std::unique_ptr<Suggestion> suggestion(new Suggestion()); | 528 std::unique_ptr<Suggestion> suggestion(new Suggestion()); |
| 524 suggestion->title = popular_site.title; | 529 suggestion->title = popular_site.title; |
| 525 suggestion->url = GURL(popular_site.url); | 530 suggestion->url = GURL(popular_site.url); |
| 526 suggestion->source = POPULAR; | 531 suggestion->source = POPULAR; |
| 527 | 532 |
| 528 popular_sites_suggestions.push_back(std::move(suggestion)); | 533 popular_sites_suggestions.push_back(std::move(suggestion)); |
| 529 if (popular_sites_suggestions.size() >= num_popular_sites_suggestions) | 534 if (popular_sites_suggestions.size() >= num_popular_sites_suggestions) |
| 530 break; | 535 break; |
| 531 } | 536 } |
| 532 } | 537 } |
| 533 return popular_sites_suggestions; | 538 return popular_sites_suggestions; |
| 534 } | 539 } |
| 535 | 540 |
| 536 void MostVisitedSites::SaveNewNTPSuggestions( | 541 void MostVisitedSites::SaveNewSuggestions( |
| 537 MostVisitedSites::SuggestionsPtrVector* personal_suggestions) { | 542 SuggestionsPtrVector* personal_suggestions) { |
| 538 MostVisitedSites::SuggestionsPtrVector whitelist_suggestions = | 543 SuggestionsPtrVector whitelist_suggestions = |
| 539 CreateWhitelistEntryPointSuggestions(*personal_suggestions); | 544 CreateWhitelistEntryPointSuggestions(*personal_suggestions); |
| 540 MostVisitedSites::SuggestionsPtrVector popular_sites_suggestions = | 545 SuggestionsPtrVector popular_sites_suggestions = |
| 541 CreatePopularSitesSuggestions(*personal_suggestions, | 546 CreatePopularSitesSuggestions(*personal_suggestions, |
| 542 whitelist_suggestions); | 547 whitelist_suggestions); |
| 548 |
| 543 size_t num_actual_tiles = personal_suggestions->size() + | 549 size_t num_actual_tiles = personal_suggestions->size() + |
| 544 whitelist_suggestions.size() + | 550 whitelist_suggestions.size() + |
| 545 popular_sites_suggestions.size(); | 551 popular_sites_suggestions.size(); |
| 546 std::vector<std::string> old_sites_url; | 552 DCHECK_LE(num_actual_tiles, static_cast<size_t>(num_sites_)); |
| 547 std::vector<bool> old_sites_is_personal; | 553 |
| 548 // TODO(treib): We used to call |GetPreviousNTPSites| here to populate | 554 SuggestionsPtrVector merged_suggestions = MergeSuggestions( |
| 549 // |old_sites_url| and |old_sites_is_personal|, but that caused problems | 555 personal_suggestions, &whitelist_suggestions, &popular_sites_suggestions); |
| 550 // (crbug.com/585391). Either figure out a way to fix them and re-enable, | |
| 551 // or properly remove the order-persisting code. crbug.com/601734 | |
| 552 MostVisitedSites::SuggestionsPtrVector merged_suggestions = MergeSuggestions( | |
| 553 personal_suggestions, &whitelist_suggestions, &popular_sites_suggestions, | |
| 554 old_sites_url, old_sites_is_personal); | |
| 555 DCHECK_EQ(num_actual_tiles, merged_suggestions.size()); | 556 DCHECK_EQ(num_actual_tiles, merged_suggestions.size()); |
| 557 |
| 556 current_suggestions_.resize(merged_suggestions.size()); | 558 current_suggestions_.resize(merged_suggestions.size()); |
| 557 for (size_t i = 0; i < merged_suggestions.size(); ++i) | 559 for (size_t i = 0; i < merged_suggestions.size(); ++i) |
| 558 std::swap(*merged_suggestions[i], current_suggestions_[i]); | 560 std::swap(*merged_suggestions[i], current_suggestions_[i]); |
| 561 |
| 559 if (received_popular_sites_) | 562 if (received_popular_sites_) |
| 560 SaveCurrentNTPSites(); | 563 SaveCurrentSuggestionsToPrefs(); |
| 561 } | 564 } |
| 562 | 565 |
| 563 // static | 566 // static |
| 564 MostVisitedSites::SuggestionsPtrVector MostVisitedSites::MergeSuggestions( | 567 MostVisitedSites::SuggestionsPtrVector MostVisitedSites::MergeSuggestions( |
| 565 MostVisitedSites::SuggestionsPtrVector* personal_suggestions, | 568 SuggestionsPtrVector* personal_suggestions, |
| 566 MostVisitedSites::SuggestionsPtrVector* whitelist_suggestions, | 569 SuggestionsPtrVector* whitelist_suggestions, |
| 567 MostVisitedSites::SuggestionsPtrVector* popular_suggestions, | 570 SuggestionsPtrVector* popular_suggestions) { |
| 568 const std::vector<std::string>& old_sites_url, | |
| 569 const std::vector<bool>& old_sites_is_personal) { | |
| 570 size_t num_personal_suggestions = personal_suggestions->size(); | 571 size_t num_personal_suggestions = personal_suggestions->size(); |
| 571 size_t num_whitelist_suggestions = whitelist_suggestions->size(); | 572 size_t num_whitelist_suggestions = whitelist_suggestions->size(); |
| 572 size_t num_popular_suggestions = popular_suggestions->size(); | 573 size_t num_popular_suggestions = popular_suggestions->size(); |
| 573 size_t num_tiles = num_popular_suggestions + num_whitelist_suggestions + | 574 size_t num_tiles = num_popular_suggestions + num_whitelist_suggestions + |
| 574 num_personal_suggestions; | 575 num_personal_suggestions; |
| 575 MostVisitedSites::SuggestionsPtrVector merged_suggestions; | 576 SuggestionsPtrVector merged_suggestions; |
| 576 merged_suggestions.resize(num_tiles); | 577 AppendSuggestions(personal_suggestions, &merged_suggestions); |
| 578 AppendSuggestions(whitelist_suggestions, &merged_suggestions); |
| 579 AppendSuggestions(popular_suggestions, &merged_suggestions); |
| 580 DCHECK_EQ(num_tiles, merged_suggestions.size()); |
| 577 | 581 |
| 578 size_t num_old_tiles = old_sites_url.size(); | |
| 579 DCHECK_LE(num_old_tiles, num_tiles); | |
| 580 DCHECK_EQ(num_old_tiles, old_sites_is_personal.size()); | |
| 581 std::vector<std::string> old_sites_host; | |
| 582 old_sites_host.reserve(num_old_tiles); | |
| 583 // Only populate the hosts for popular suggestions as only they can be | |
| 584 // replaced by host. Personal suggestions require an exact url match to be | |
| 585 // replaced. | |
| 586 for (size_t i = 0; i < num_old_tiles; ++i) { | |
| 587 old_sites_host.push_back(old_sites_is_personal[i] | |
| 588 ? std::string() | |
| 589 : GURL(old_sites_url[i]).host()); | |
| 590 } | |
| 591 | |
| 592 // Insert personal suggestions if they existed previously. | |
| 593 std::vector<size_t> new_personal_suggestions = InsertMatchingSuggestions( | |
| 594 personal_suggestions, &merged_suggestions, old_sites_url, old_sites_host); | |
| 595 // Insert whitelist suggestions if they existed previously. | |
| 596 std::vector<size_t> new_whitelist_suggestions = | |
| 597 InsertMatchingSuggestions(whitelist_suggestions, &merged_suggestions, | |
| 598 old_sites_url, old_sites_host); | |
| 599 // Insert popular suggestions if they existed previously. | |
| 600 std::vector<size_t> new_popular_suggestions = InsertMatchingSuggestions( | |
| 601 popular_suggestions, &merged_suggestions, old_sites_url, old_sites_host); | |
| 602 // Insert leftover personal suggestions. | |
| 603 size_t filled_so_far = InsertAllSuggestions( | |
| 604 0, new_personal_suggestions, personal_suggestions, &merged_suggestions); | |
| 605 // Insert leftover whitelist suggestions. | |
| 606 filled_so_far = | |
| 607 InsertAllSuggestions(filled_so_far, new_whitelist_suggestions, | |
| 608 whitelist_suggestions, &merged_suggestions); | |
| 609 // Insert leftover popular suggestions. | |
| 610 InsertAllSuggestions(filled_so_far, new_popular_suggestions, | |
| 611 popular_suggestions, &merged_suggestions); | |
| 612 return merged_suggestions; | 582 return merged_suggestions; |
| 613 } | 583 } |
| 614 | 584 |
| 615 void MostVisitedSites::GetPreviousNTPSites( | 585 // TODO(treib): Once we use SuggestionsVector (non-Ptr) everywhere, move this |
| 616 size_t num_tiles, | 586 // into an anonymous namespace. |
| 617 std::vector<std::string>* old_sites_url, | 587 // static |
| 618 std::vector<bool>* old_sites_is_personal) const { | 588 void MostVisitedSites::AppendSuggestions(SuggestionsPtrVector* src, |
| 619 const base::ListValue* url_list = prefs_->GetList( | 589 SuggestionsPtrVector* dst) { |
| 620 ntp_tiles::prefs::kNTPSuggestionsURL); | 590 dst->insert(dst->end(), |
| 621 const base::ListValue* source_list = | 591 std::make_move_iterator(src->begin()), |
| 622 prefs_->GetList(ntp_tiles::prefs::kNTPSuggestionsIsPersonal); | 592 std::make_move_iterator(src->end())); |
| 623 DCHECK_EQ(url_list->GetSize(), source_list->GetSize()); | |
| 624 if (url_list->GetSize() < num_tiles) | |
| 625 num_tiles = url_list->GetSize(); | |
| 626 if (num_tiles == 0) { | |
| 627 // No fallback required as Personal suggestions take precedence anyway. | |
| 628 return; | |
| 629 } | |
| 630 old_sites_url->reserve(num_tiles); | |
| 631 old_sites_is_personal->reserve(num_tiles); | |
| 632 for (size_t i = 0; i < num_tiles; ++i) { | |
| 633 std::string url_string; | |
| 634 bool success = url_list->GetString(i, &url_string); | |
| 635 DCHECK(success); | |
| 636 old_sites_url->push_back(url_string); | |
| 637 bool is_personal; | |
| 638 success = source_list->GetBoolean(i, &is_personal); | |
| 639 DCHECK(success); | |
| 640 old_sites_is_personal->push_back(is_personal); | |
| 641 } | |
| 642 } | 593 } |
| 643 | 594 |
| 644 void MostVisitedSites::SaveCurrentNTPSites() { | 595 void MostVisitedSites::SaveCurrentSuggestionsToPrefs() { |
| 645 base::ListValue url_list; | 596 base::ListValue url_list; |
| 646 base::ListValue source_list; | 597 base::ListValue source_list; |
| 647 for (const auto& suggestion : current_suggestions_) { | 598 for (const auto& suggestion : current_suggestions_) { |
| 648 url_list.AppendString(suggestion.url.spec()); | 599 url_list.AppendString(suggestion.url.spec()); |
| 649 source_list.AppendBoolean(suggestion.source != MostVisitedSites::POPULAR); | 600 source_list.AppendBoolean(suggestion.source != POPULAR); |
| 650 } | 601 } |
| 651 prefs_->Set(ntp_tiles::prefs::kNTPSuggestionsIsPersonal, source_list); | 602 prefs_->Set(ntp_tiles::prefs::kNTPSuggestionsIsPersonal, source_list); |
| 652 prefs_->Set(ntp_tiles::prefs::kNTPSuggestionsURL, url_list); | 603 prefs_->Set(ntp_tiles::prefs::kNTPSuggestionsURL, url_list); |
| 653 } | 604 } |
| 654 | 605 |
| 655 // static | |
| 656 std::vector<size_t> MostVisitedSites::InsertMatchingSuggestions( | |
| 657 MostVisitedSites::SuggestionsPtrVector* src_suggestions, | |
| 658 MostVisitedSites::SuggestionsPtrVector* dst_suggestions, | |
| 659 const std::vector<std::string>& match_urls, | |
| 660 const std::vector<std::string>& match_hosts) { | |
| 661 std::vector<size_t> unmatched_suggestions; | |
| 662 size_t num_src_suggestions = src_suggestions->size(); | |
| 663 size_t num_matchers = match_urls.size(); | |
| 664 for (size_t i = 0; i < num_src_suggestions; ++i) { | |
| 665 size_t position; | |
| 666 for (position = 0; position < num_matchers; ++position) { | |
| 667 if ((*dst_suggestions)[position] != nullptr) | |
| 668 continue; | |
| 669 if (match_urls[position] == (*src_suggestions)[i]->url.spec()) | |
| 670 break; | |
| 671 // match_hosts is only populated for suggestions which can be replaced by | |
| 672 // host matching like popular suggestions. | |
| 673 if (match_hosts[position] == (*src_suggestions)[i]->url.host()) | |
| 674 break; | |
| 675 } | |
| 676 if (position == num_matchers) { | |
| 677 unmatched_suggestions.push_back(i); | |
| 678 } else { | |
| 679 // A move is required as the source and destination containers own the | |
| 680 // elements. | |
| 681 std::swap((*dst_suggestions)[position], (*src_suggestions)[i]); | |
| 682 } | |
| 683 } | |
| 684 return unmatched_suggestions; | |
| 685 } | |
| 686 | |
| 687 // static | |
| 688 size_t MostVisitedSites::InsertAllSuggestions( | |
| 689 size_t start_position, | |
| 690 const std::vector<size_t>& insert_positions, | |
| 691 std::vector<std::unique_ptr<Suggestion>>* src_suggestions, | |
| 692 std::vector<std::unique_ptr<Suggestion>>* dst_suggestions) { | |
| 693 size_t num_inserts = insert_positions.size(); | |
| 694 size_t num_dests = dst_suggestions->size(); | |
| 695 | |
| 696 size_t src_pos = 0; | |
| 697 size_t i = start_position; | |
| 698 for (; i < num_dests && src_pos < num_inserts; ++i) { | |
| 699 if ((*dst_suggestions)[i] != nullptr) | |
| 700 continue; | |
| 701 size_t src = insert_positions[src_pos++]; | |
| 702 std::swap((*dst_suggestions)[i], (*src_suggestions)[src]); | |
| 703 } | |
| 704 // Return destination positions filled so far which becomes the start_position | |
| 705 // for future runs. | |
| 706 return i; | |
| 707 } | |
| 708 | |
| 709 void MostVisitedSites::NotifyMostVisitedURLsObserver() { | 606 void MostVisitedSites::NotifyMostVisitedURLsObserver() { |
| 710 size_t num_suggestions = current_suggestions_.size(); | |
| 711 if (received_most_visited_sites_ && received_popular_sites_ && | 607 if (received_most_visited_sites_ && received_popular_sites_ && |
| 712 !recorded_uma_) { | 608 !recorded_uma_) { |
| 713 RecordImpressionUMAMetrics(); | 609 RecordImpressionUMAMetrics(); |
| 714 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.NumberOfTiles", num_suggestions); | 610 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.NumberOfTiles", |
| 611 current_suggestions_.size()); |
| 715 recorded_uma_ = true; | 612 recorded_uma_ = true; |
| 716 } | 613 } |
| 717 | 614 |
| 718 if (!observer_) | 615 if (!observer_) |
| 719 return; | 616 return; |
| 720 | 617 |
| 721 observer_->OnMostVisitedURLsAvailable(current_suggestions_); | 618 observer_->OnMostVisitedURLsAvailable(current_suggestions_); |
| 722 } | 619 } |
| 723 | 620 |
| 724 void MostVisitedSites::OnPopularSitesAvailable(bool success) { | 621 void MostVisitedSites::OnPopularSitesAvailable(bool success) { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 748 | 645 |
| 749 void MostVisitedSites::TopSitesLoaded(TopSites* top_sites) {} | 646 void MostVisitedSites::TopSitesLoaded(TopSites* top_sites) {} |
| 750 | 647 |
| 751 void MostVisitedSites::TopSitesChanged(TopSites* top_sites, | 648 void MostVisitedSites::TopSitesChanged(TopSites* top_sites, |
| 752 ChangeReason change_reason) { | 649 ChangeReason change_reason) { |
| 753 if (mv_source_ == TOP_SITES) { | 650 if (mv_source_ == TOP_SITES) { |
| 754 // The displayed suggestions are invalidated. | 651 // The displayed suggestions are invalidated. |
| 755 InitiateTopSitesQuery(); | 652 InitiateTopSitesQuery(); |
| 756 } | 653 } |
| 757 } | 654 } |
| OLD | NEW |