OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "components/ntp_snippets/ntp_snippets_service.h" | 5 #include "components/ntp_snippets/ntp_snippets_service.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <iterator> | 8 #include <iterator> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
254 FetchSnippetsFromHosts(GetSuggestionsHosts(), force_request); | 254 FetchSnippetsFromHosts(GetSuggestionsHosts(), force_request); |
255 else | 255 else |
256 fetch_after_load_ = true; | 256 fetch_after_load_ = true; |
257 } | 257 } |
258 | 258 |
259 void NTPSnippetsService::FetchSnippetsFromHosts( | 259 void NTPSnippetsService::FetchSnippetsFromHosts( |
260 const std::set<std::string>& hosts, | 260 const std::set<std::string>& hosts, |
261 bool force_request) { | 261 bool force_request) { |
262 if (!ready()) | 262 if (!ready()) |
263 return; | 263 return; |
| 264 |
| 265 if (snippets_.empty()) |
| 266 UpdateCategoryStatus(CategoryStatus::AVAILABLE_LOADING); |
| 267 |
264 snippets_fetcher_->FetchSnippetsFromHosts(hosts, application_language_code_, | 268 snippets_fetcher_->FetchSnippetsFromHosts(hosts, application_language_code_, |
265 kMaxSnippetCount, force_request); | 269 kMaxSnippetCount, force_request); |
266 } | 270 } |
267 | 271 |
268 void NTPSnippetsService::RescheduleFetching() { | 272 void NTPSnippetsService::RescheduleFetching() { |
269 // The scheduler only exists on Android so far, it's null on other platforms. | 273 // The scheduler only exists on Android so far, it's null on other platforms. |
270 if (!scheduler_) | 274 if (!scheduler_) |
271 return; | 275 return; |
272 | 276 |
273 if (ready()) { | 277 if (ready()) { |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
414 }); | 418 }); |
415 | 419 |
416 ClearExpiredSnippets(); | 420 ClearExpiredSnippets(); |
417 FinishInitialization(); | 421 FinishInitialization(); |
418 } | 422 } |
419 | 423 |
420 void NTPSnippetsService::OnDatabaseError() { | 424 void NTPSnippetsService::OnDatabaseError() { |
421 EnterState(State::SHUT_DOWN, CategoryStatus::LOADING_ERROR); | 425 EnterState(State::SHUT_DOWN, CategoryStatus::LOADING_ERROR); |
422 } | 426 } |
423 | 427 |
| 428 // TODO(dgn): name clash between content suggestions and suggestions hosts. |
| 429 // method name should be changed. |
424 void NTPSnippetsService::OnSuggestionsChanged( | 430 void NTPSnippetsService::OnSuggestionsChanged( |
425 const SuggestionsProfile& suggestions) { | 431 const SuggestionsProfile& suggestions) { |
426 DCHECK(initialized()); | 432 DCHECK(initialized()); |
427 | 433 |
428 std::set<std::string> hosts = GetSuggestionsHostsImpl(suggestions); | 434 std::set<std::string> hosts = GetSuggestionsHostsImpl(suggestions); |
429 if (hosts == GetSnippetHostsFromPrefs()) | 435 if (hosts == GetSnippetHostsFromPrefs()) |
430 return; | 436 return; |
431 | 437 |
432 // Remove existing snippets that aren't in the suggestions anymore. | 438 // Remove existing snippets that aren't in the suggestions anymore. |
433 // TODO(treib,maybelle): If there is another source with an allowed host, | 439 // TODO(treib,maybelle): If there is another source with an allowed host, |
434 // then we should fall back to that. | 440 // then we should fall back to that. |
435 // First, move them over into |to_delete|. | 441 // First, move them over into |to_delete|. |
436 NTPSnippet::PtrVector to_delete; | 442 NTPSnippet::PtrVector to_delete; |
437 for (std::unique_ptr<NTPSnippet>& snippet : snippets_) { | 443 for (std::unique_ptr<NTPSnippet>& snippet : snippets_) { |
438 if (!hosts.count(snippet->best_source().url.host())) | 444 if (!hosts.count(snippet->best_source().url.host())) |
439 to_delete.emplace_back(std::move(snippet)); | 445 to_delete.emplace_back(std::move(snippet)); |
440 } | 446 } |
441 Compact(&snippets_); | 447 Compact(&snippets_); |
442 // Then delete the removed snippets from the database. | 448 // Then delete the removed snippets from the database. |
443 database_->DeleteSnippets(to_delete); | 449 database_->DeleteSnippets(to_delete); |
444 | 450 |
445 StoreSnippetHostsToPrefs(hosts); | 451 StoreSnippetHostsToPrefs(hosts); |
446 | 452 |
| 453 // We removed some suggestions, so we want to let the client know about that. |
| 454 // The fetch might take a long time or not complete so we don't want to wait |
| 455 // for its callback. |
447 NotifyNewSuggestions(); | 456 NotifyNewSuggestions(); |
448 | 457 |
449 FetchSnippetsFromHosts(hosts, /*force_request=*/false); | 458 FetchSnippetsFromHosts(hosts, /*force_request=*/false); |
450 } | 459 } |
451 | 460 |
452 void NTPSnippetsService::OnFetchFinished( | 461 void NTPSnippetsService::OnFetchFinished( |
453 NTPSnippetsFetcher::OptionalSnippets snippets) { | 462 NTPSnippetsFetcher::OptionalSnippets snippets) { |
454 if (!ready()) | 463 if (!ready()) |
455 return; | 464 return; |
456 | 465 |
| 466 DCHECK(category_status_ == CategoryStatus::AVAILABLE || |
| 467 category_status_ == CategoryStatus::AVAILABLE_LOADING); |
| 468 |
457 if (snippets) { | 469 if (snippets) { |
458 // Sparse histogram used because the number of snippets is small (bound by | 470 // Sparse histogram used because the number of snippets is small (bound by |
459 // kMaxSnippetCount). | 471 // kMaxSnippetCount). |
460 DCHECK_LE(snippets->size(), static_cast<size_t>(kMaxSnippetCount)); | 472 DCHECK_LE(snippets->size(), static_cast<size_t>(kMaxSnippetCount)); |
461 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticlesFetched", | 473 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticlesFetched", |
462 snippets->size()); | 474 snippets->size()); |
463 MergeSnippets(std::move(*snippets)); | 475 MergeSnippets(std::move(*snippets)); |
464 } | 476 } |
465 | 477 |
466 ClearExpiredSnippets(); | 478 ClearExpiredSnippets(); |
467 | 479 |
468 // If there are more snippets than we want to show, delete the extra ones. | 480 // If there are more snippets than we want to show, delete the extra ones. |
469 if (snippets_.size() > kMaxSnippetCount) { | 481 if (snippets_.size() > kMaxSnippetCount) { |
470 NTPSnippet::PtrVector to_delete( | 482 NTPSnippet::PtrVector to_delete( |
471 std::make_move_iterator(snippets_.begin() + kMaxSnippetCount), | 483 std::make_move_iterator(snippets_.begin() + kMaxSnippetCount), |
472 std::make_move_iterator(snippets_.end())); | 484 std::make_move_iterator(snippets_.end())); |
473 snippets_.resize(kMaxSnippetCount); | 485 snippets_.resize(kMaxSnippetCount); |
474 database_->DeleteSnippets(to_delete); | 486 database_->DeleteSnippets(to_delete); |
475 } | 487 } |
476 | 488 |
477 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles", | 489 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles", |
478 snippets_.size()); | 490 snippets_.size()); |
479 if (snippets_.empty() && !dismissed_snippets_.empty()) { | 491 if (snippets_.empty() && !dismissed_snippets_.empty()) { |
480 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded", | 492 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded", |
481 dismissed_snippets_.size()); | 493 dismissed_snippets_.size()); |
482 } | 494 } |
483 | 495 |
| 496 UpdateCategoryStatus(CategoryStatus::AVAILABLE); |
484 NotifyNewSuggestions(); | 497 NotifyNewSuggestions(); |
485 } | 498 } |
486 | 499 |
487 void NTPSnippetsService::MergeSnippets(NTPSnippet::PtrVector new_snippets) { | 500 void NTPSnippetsService::MergeSnippets(NTPSnippet::PtrVector new_snippets) { |
488 DCHECK(ready()); | 501 DCHECK(ready()); |
489 | 502 |
490 // Remove new snippets that we already have, or that have been dismissed. | 503 // Remove new snippets that we already have, or that have been dismissed. |
491 std::set<std::string> old_snippet_ids; | 504 std::set<std::string> old_snippet_ids; |
492 InsertAllIDs(dismissed_snippets_, &old_snippet_ids); | 505 InsertAllIDs(dismissed_snippets_, &old_snippet_ids); |
493 InsertAllIDs(snippets_, &old_snippet_ids); | 506 InsertAllIDs(snippets_, &old_snippet_ids); |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
654 | 667 |
655 const NTPSnippet& snippet = *it->get(); | 668 const NTPSnippet& snippet = *it->get(); |
656 image_fetcher_->StartOrQueueNetworkRequest( | 669 image_fetcher_->StartOrQueueNetworkRequest( |
657 snippet.id(), snippet.salient_image_url(), callback); | 670 snippet.id(), snippet.salient_image_url(), callback); |
658 } | 671 } |
659 | 672 |
660 void NTPSnippetsService::EnterStateEnabled(bool fetch_snippets) { | 673 void NTPSnippetsService::EnterStateEnabled(bool fetch_snippets) { |
661 if (fetch_snippets) | 674 if (fetch_snippets) |
662 FetchSnippets(/*force_request=*/false); | 675 FetchSnippets(/*force_request=*/false); |
663 | 676 |
| 677 // FetchSnippets should set the status to |AVAILABLE_LOADING| if relevant, |
| 678 // otherwise we transition to |AVAILABLE| here. |
| 679 if (category_status_ != CategoryStatus::AVAILABLE_LOADING) |
| 680 UpdateCategoryStatus(CategoryStatus::AVAILABLE); |
| 681 |
664 // If host restrictions are enabled, register for host list updates. | 682 // If host restrictions are enabled, register for host list updates. |
665 // |suggestions_service_| can be null in tests. | 683 // |suggestions_service_| can be null in tests. |
666 if (snippets_fetcher_->UsesHostRestrictions() && suggestions_service_) { | 684 if (snippets_fetcher_->UsesHostRestrictions() && suggestions_service_) { |
667 suggestions_service_subscription_ = | 685 suggestions_service_subscription_ = |
668 suggestions_service_->AddCallback(base::Bind( | 686 suggestions_service_->AddCallback(base::Bind( |
669 &NTPSnippetsService::OnSuggestionsChanged, base::Unretained(this))); | 687 &NTPSnippetsService::OnSuggestionsChanged, base::Unretained(this))); |
670 } | 688 } |
671 | 689 |
672 RescheduleFetching(); | 690 RescheduleFetching(); |
673 } | 691 } |
(...skipping 27 matching lines...) Expand all Loading... |
701 image_fetcher_->SetImageFetcherDelegate(this); | 719 image_fetcher_->SetImageFetcherDelegate(this); |
702 image_fetcher_->SetDataUseServiceName( | 720 image_fetcher_->SetDataUseServiceName( |
703 data_use_measurement::DataUseUserData::NTP_SNIPPETS); | 721 data_use_measurement::DataUseUserData::NTP_SNIPPETS); |
704 } | 722 } |
705 | 723 |
706 // Note: Initializing the status service will run the callback right away with | 724 // Note: Initializing the status service will run the callback right away with |
707 // the current state. | 725 // the current state. |
708 snippets_status_service_->Init(base::Bind( | 726 snippets_status_service_->Init(base::Bind( |
709 &NTPSnippetsService::OnDisabledReasonChanged, base::Unretained(this))); | 727 &NTPSnippetsService::OnDisabledReasonChanged, base::Unretained(this))); |
710 | 728 |
| 729 // Always notify here even if we got nothing from the database, because we |
| 730 // don't know how long the fetch will take or if it will even complete. |
711 NotifyNewSuggestions(); | 731 NotifyNewSuggestions(); |
712 } | 732 } |
713 | 733 |
714 void NTPSnippetsService::OnDisabledReasonChanged( | 734 void NTPSnippetsService::OnDisabledReasonChanged( |
715 DisabledReason disabled_reason) { | 735 DisabledReason disabled_reason) { |
716 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, | 736 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, |
717 NTPSnippetsServiceDisabledReasonChanged(disabled_reason)); | 737 NTPSnippetsServiceDisabledReasonChanged(disabled_reason)); |
718 | 738 |
719 switch (disabled_reason) { | 739 switch (disabled_reason) { |
720 case DisabledReason::NONE: | 740 case DisabledReason::NONE: |
721 EnterState(State::READY, CategoryStatus::AVAILABLE); | 741 // Do not change the status. That will be done in EnterStateEnabled() |
| 742 EnterState(State::READY, category_status_); |
722 break; | 743 break; |
723 | 744 |
724 case DisabledReason::EXPLICITLY_DISABLED: | 745 case DisabledReason::EXPLICITLY_DISABLED: |
725 EnterState(State::DISABLED, CategoryStatus::CATEGORY_EXPLICITLY_DISABLED); | 746 EnterState(State::DISABLED, CategoryStatus::CATEGORY_EXPLICITLY_DISABLED); |
726 break; | 747 break; |
727 | 748 |
728 case DisabledReason::SIGNED_OUT: | 749 case DisabledReason::SIGNED_OUT: |
729 EnterState(State::DISABLED, CategoryStatus::SIGNED_OUT); | 750 EnterState(State::DISABLED, CategoryStatus::SIGNED_OUT); |
730 break; | 751 break; |
731 } | 752 } |
732 } | 753 } |
733 | 754 |
734 void NTPSnippetsService::EnterState(State state, CategoryStatus status) { | 755 void NTPSnippetsService::EnterState(State state, CategoryStatus status) { |
735 if (status != category_status_) { | 756 UpdateCategoryStatus(status); |
736 category_status_ = status; | |
737 NotifyCategoryStatusChanged(); | |
738 } | |
739 | 757 |
740 if (state == state_) | 758 if (state == state_) |
741 return; | 759 return; |
742 | 760 |
743 switch (state) { | 761 switch (state) { |
744 case State::NOT_INITED: | 762 case State::NOT_INITED: |
745 // Initial state, it should not be possible to get back there. | 763 // Initial state, it should not be possible to get back there. |
746 NOTREACHED(); | 764 NOTREACHED(); |
747 return; | 765 return; |
748 | 766 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
793 suggestion.set_snippet_text(base::UTF8ToUTF16(snippet->snippet())); | 811 suggestion.set_snippet_text(base::UTF8ToUTF16(snippet->snippet())); |
794 suggestion.set_publish_date(snippet->publish_date()); | 812 suggestion.set_publish_date(snippet->publish_date()); |
795 suggestion.set_publisher_name( | 813 suggestion.set_publisher_name( |
796 base::UTF8ToUTF16(snippet->best_source().publisher_name)); | 814 base::UTF8ToUTF16(snippet->best_source().publisher_name)); |
797 suggestion.set_score(snippet->score()); | 815 suggestion.set_score(snippet->score()); |
798 result.emplace_back(std::move(suggestion)); | 816 result.emplace_back(std::move(suggestion)); |
799 } | 817 } |
800 observer_->OnNewSuggestions(provided_category_, std::move(result)); | 818 observer_->OnNewSuggestions(provided_category_, std::move(result)); |
801 } | 819 } |
802 | 820 |
803 void NTPSnippetsService::NotifyCategoryStatusChanged() { | 821 void NTPSnippetsService::UpdateCategoryStatus(CategoryStatus status) { |
| 822 if (status == category_status_) |
| 823 return; |
| 824 |
| 825 category_status_ = status; |
804 if (observer_) { | 826 if (observer_) { |
805 observer_->OnCategoryStatusChanged(provided_category_, category_status_); | 827 observer_->OnCategoryStatusChanged(provided_category_, category_status_); |
806 } | 828 } |
807 } | 829 } |
808 | 830 |
809 } // namespace ntp_snippets | 831 } // namespace ntp_snippets |
OLD | NEW |