Chromium Code Reviews| 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/remote/ntp_snippets_service.h" | 5 #include "components/ntp_snippets/remote/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 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 150 } | 150 } |
| 151 | 151 |
| 152 void RemoveNullPointers(NTPSnippet::PtrVector* snippets) { | 152 void RemoveNullPointers(NTPSnippet::PtrVector* snippets) { |
| 153 snippets->erase( | 153 snippets->erase( |
| 154 std::remove_if( | 154 std::remove_if( |
| 155 snippets->begin(), snippets->end(), | 155 snippets->begin(), snippets->end(), |
| 156 [](const std::unique_ptr<NTPSnippet>& snippet) { return !snippet; }), | 156 [](const std::unique_ptr<NTPSnippet>& snippet) { return !snippet; }), |
| 157 snippets->end()); | 157 snippets->end()); |
| 158 } | 158 } |
| 159 | 159 |
| 160 void AssignExpiryAndPublishDates(NTPSnippet::PtrVector* snippets) { | |
| 161 for (std::unique_ptr<NTPSnippet>& snippet : *snippets) { | |
| 162 if (snippet->publish_date().is_null()) | |
| 163 snippet->set_publish_date(base::Time::Now()); | |
| 164 if (snippet->expiry_date().is_null()) { | |
| 165 snippet->set_expiry_date( | |
| 166 snippet->publish_date() + | |
| 167 base::TimeDelta::FromMinutes(kDefaultExpiryTimeMins)); | |
| 168 } | |
| 169 } | |
| 170 } | |
| 171 | |
| 172 void RemoveIncompleteSnippets(NTPSnippet::PtrVector* snippets) { | |
| 173 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 174 switches::kAddIncompleteSnippets)) { | |
| 175 return; | |
| 176 } | |
| 177 int num_snippets = snippets->size(); | |
| 178 // Remove snippets that do not have all the info we need to display it to | |
| 179 // the user. | |
| 180 snippets->erase( | |
| 181 std::remove_if(snippets->begin(), snippets->end(), | |
| 182 [](const std::unique_ptr<NTPSnippet>& snippet) { | |
| 183 return !snippet->is_complete(); | |
| 184 }), | |
| 185 snippets->end()); | |
| 186 int num_snippets_dismissed = num_snippets - snippets->size(); | |
|
vitaliii
2016/11/01 23:29:57
s/dismissed/removed?
"dismissed" is usually used i
fhorschig
2016/11/02 05:05:27
Done in CL 2466863003.
| |
| 187 UMA_HISTOGRAM_BOOLEAN("NewTabPage.Snippets.IncompleteSnippetsAfterFetch", | |
| 188 num_snippets_dismissed > 0); | |
| 189 if (num_snippets_dismissed > 0) { | |
| 190 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumIncompleteSnippets", | |
| 191 num_snippets_dismissed); | |
| 192 } | |
| 193 } | |
| 194 | |
| 195 NTPSnippetsService::FetchedMoreCallback NullCallback() { | |
| 196 return NTPSnippetsService::FetchedMoreCallback(); | |
| 197 } | |
| 198 | |
| 160 } // namespace | 199 } // namespace |
| 161 | 200 |
| 162 NTPSnippetsService::NTPSnippetsService( | 201 NTPSnippetsService::NTPSnippetsService( |
| 163 Observer* observer, | 202 Observer* observer, |
| 164 CategoryFactory* category_factory, | 203 CategoryFactory* category_factory, |
| 165 PrefService* pref_service, | 204 PrefService* pref_service, |
| 166 const std::string& application_language_code, | 205 const std::string& application_language_code, |
| 167 const UserClassifier* user_classifier, | 206 const UserClassifier* user_classifier, |
| 168 NTPSnippetsScheduler* scheduler, | 207 NTPSnippetsScheduler* scheduler, |
| 169 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher, | 208 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher, |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 236 void NTPSnippetsService::FetchSnippets(bool interactive_request) { | 275 void NTPSnippetsService::FetchSnippets(bool interactive_request) { |
| 237 if (ready()) | 276 if (ready()) |
| 238 FetchSnippetsFromHosts(std::set<std::string>(), interactive_request); | 277 FetchSnippetsFromHosts(std::set<std::string>(), interactive_request); |
| 239 else | 278 else |
| 240 fetch_when_ready_ = true; | 279 fetch_when_ready_ = true; |
| 241 } | 280 } |
| 242 | 281 |
| 243 void NTPSnippetsService::FetchSnippetsFromHosts( | 282 void NTPSnippetsService::FetchSnippetsFromHosts( |
| 244 const std::set<std::string>& hosts, | 283 const std::set<std::string>& hosts, |
| 245 bool interactive_request) { | 284 bool interactive_request) { |
| 285 FetchSnippetsFromHostsImpl(hosts, interactive_request, | |
| 286 /*fetch_more=*/false, | |
| 287 base::Optional<Category>(), | |
| 288 NullCallback()); | |
|
vitaliii
2016/11/01 23:29:57
Actually writing here |NTPSnippetsService::Fetched
fhorschig
2016/11/02 05:05:27
Done in 2446163005.
| |
| 289 } | |
| 290 | |
| 291 void NTPSnippetsService::FetchMore(const Category& category, | |
| 292 const FetchedMoreCallback& callback) { | |
| 293 FetchSnippetsFromHostsImpl(std::set<std::string>(), | |
| 294 /*interactive_request=*/true, | |
| 295 /*fetch_more=*/true, | |
| 296 base::Optional<Category>(category), | |
| 297 callback); | |
| 298 } | |
| 299 | |
| 300 void NTPSnippetsService::FetchSnippetsFromHostsImpl( | |
| 301 const std::set<std::string>& hosts, | |
| 302 bool interactive_request, | |
| 303 bool fetch_more, | |
| 304 base::Optional<Category> exclusive_category, | |
| 305 const FetchedMoreCallback& callback) { | |
| 246 if (!ready()) | 306 if (!ready()) |
| 247 return; | 307 return; |
| 248 | 308 |
| 249 // Empty categories are marked as loading; others are unchanged. | |
| 250 for (const auto& item : categories_) { | |
| 251 Category category = item.first; | |
| 252 const CategoryContent& content = item.second; | |
| 253 if (content.snippets.empty()) | |
| 254 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE_LOADING); | |
| 255 } | |
| 256 | |
| 257 NTPSnippetsFetcher::Params params; | 309 NTPSnippetsFetcher::Params params; |
| 258 params.language_code = application_language_code_; | 310 params.language_code = application_language_code_; |
| 259 params.count_to_fetch = kMaxSnippetCount; | 311 params.count_to_fetch = kMaxSnippetCount; |
| 260 params.hosts = hosts; | 312 params.hosts = hosts; |
| 261 params.interactive_request = interactive_request; | 313 params.interactive_request = interactive_request; |
| 314 params.exclusive_category = exclusive_category; | |
| 315 params.excluded_ids = CollectIdsToExclude(fetch_more); | |
| 316 params.snippets_available_callback = | |
| 317 base::BindOnce(&NTPSnippetsService::OnFetchFinished, | |
| 318 base::Unretained(this), | |
| 319 fetch_more, | |
| 320 std::move(callback)); | |
| 321 | |
| 322 MarkEmptyCategoriesAsLoading(¶ms); | |
| 323 | |
| 324 snippets_fetcher_->FetchSnippets(params); | |
| 325 } | |
| 326 | |
| 327 std::set<std::string> NTPSnippetsService::CollectIdsToExclude(bool fetch_more) { | |
| 328 std::set<std::string> ids; | |
| 262 for (const auto& item : categories_) { | 329 for (const auto& item : categories_) { |
| 263 const CategoryContent& content = item.second; | 330 const CategoryContent& content = item.second; |
| 264 for (const auto& snippet : content.dismissed) | 331 for (const auto& snippet : content.dismissed) |
| 265 params.excluded_ids.insert(snippet->id()); | 332 ids.insert(snippet->id()); |
| 333 if (!fetch_more) | |
| 334 continue; | |
| 335 for (const auto& snippet : content.archived) | |
| 336 ids.insert(snippet->id()); | |
| 337 for (const auto& snippet : content.snippets) | |
| 338 ids.insert(snippet->id()); | |
| 266 } | 339 } |
| 267 snippets_fetcher_->FetchSnippets(params); | 340 return ids; |
| 341 } | |
| 342 | |
| 343 void NTPSnippetsService::MarkEmptyCategoriesAsLoading( | |
| 344 NTPSnippetsFetcher::Params* params) { | |
| 345 for (const auto& item : categories_) { | |
| 346 Category category = item.first; | |
| 347 const CategoryContent& content = item.second; | |
| 348 for (const auto& snippet : content.dismissed) | |
| 349 params->excluded_ids.insert(snippet->id()); | |
|
vitaliii
2016/11/01 23:29:57
I cannot understand why this is done here.
First,
fhorschig
2016/11/02 05:05:27
This is a false merge. It is completely dropped la
| |
| 350 if (content.snippets.empty()) | |
| 351 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE_LOADING); | |
| 352 } | |
| 268 } | 353 } |
| 269 | 354 |
| 270 void NTPSnippetsService::RescheduleFetching(bool force) { | 355 void NTPSnippetsService::RescheduleFetching(bool force) { |
| 271 // The scheduler only exists on Android so far, it's null on other platforms. | 356 // The scheduler only exists on Android so far, it's null on other platforms. |
| 272 if (!scheduler_) | 357 if (!scheduler_) |
| 273 return; | 358 return; |
| 274 | 359 |
| 275 if (ready()) { | 360 if (ready()) { |
| 276 base::TimeDelta old_interval_wifi = | 361 base::TimeDelta old_interval_wifi = |
| 277 base::TimeDelta::FromInternalValue(pref_service_->GetInt64( | 362 base::TimeDelta::FromInternalValue(pref_service_->GetInt64( |
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 522 ClearOrphanedImages(); | 607 ClearOrphanedImages(); |
| 523 FinishInitialization(); | 608 FinishInitialization(); |
| 524 } | 609 } |
| 525 | 610 |
| 526 void NTPSnippetsService::OnDatabaseError() { | 611 void NTPSnippetsService::OnDatabaseError() { |
| 527 EnterState(State::ERROR_OCCURRED); | 612 EnterState(State::ERROR_OCCURRED); |
| 528 UpdateAllCategoryStatus(CategoryStatus::LOADING_ERROR); | 613 UpdateAllCategoryStatus(CategoryStatus::LOADING_ERROR); |
| 529 } | 614 } |
| 530 | 615 |
| 531 void NTPSnippetsService::OnFetchFinished( | 616 void NTPSnippetsService::OnFetchFinished( |
| 617 bool fetched_more, | |
| 618 const FetchedMoreCallback& fetched_more_callback, | |
| 532 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories) { | 619 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories) { |
| 533 if (!ready()) | 620 if (!ready()) |
| 534 return; | 621 return; |
| 535 | 622 |
| 536 // Mark all categories as not provided by the server in the latest fetch. The | 623 // Mark all categories as not provided by the server in the latest fetch. The |
| 537 // ones we got will be marked again below. | 624 // ones we got will be marked again below. |
| 538 for (auto& item : categories_) { | 625 for (auto& item : categories_) { |
| 539 CategoryContent* content = &item.second; | 626 CategoryContent* content = &item.second; |
| 540 content->provided_by_server = false; | 627 content->provided_by_server = false; |
| 541 } | 628 } |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 566 categories_[category].provided_by_server = true; | 653 categories_[category].provided_by_server = true; |
| 567 | 654 |
| 568 // TODO(tschumann): Remove this histogram once we only talk to the content | 655 // TODO(tschumann): Remove this histogram once we only talk to the content |
| 569 // suggestions cloud backend. | 656 // suggestions cloud backend. |
| 570 if (category == articles_category_) { | 657 if (category == articles_category_) { |
| 571 UMA_HISTOGRAM_SPARSE_SLOWLY( | 658 UMA_HISTOGRAM_SPARSE_SLOWLY( |
| 572 "NewTabPage.Snippets.NumArticlesFetched", | 659 "NewTabPage.Snippets.NumArticlesFetched", |
| 573 std::min(fetched_category.snippets.size(), | 660 std::min(fetched_category.snippets.size(), |
| 574 static_cast<size_t>(kMaxSnippetCount + 1))); | 661 static_cast<size_t>(kMaxSnippetCount + 1))); |
| 575 } | 662 } |
| 576 ReplaceSnippets(category, std::move(fetched_category.snippets)); | 663 IncludeSnippets(category, std::move(fetched_category.snippets), |
| 664 /*replace_snippets=*/!fetched_more); | |
| 577 } | 665 } |
| 578 } | 666 } |
| 579 | 667 |
| 580 // We might have gotten new categories (or updated the titles of existing | 668 // We might have gotten new categories (or updated the titles of existing |
| 581 // ones), so update the pref. | 669 // ones), so update the pref. |
| 582 StoreCategoriesToPrefs(); | 670 StoreCategoriesToPrefs(); |
| 583 | 671 |
| 584 for (const auto& item : categories_) { | 672 for (const auto& item : categories_) { |
| 585 Category category = item.first; | 673 Category category = item.first; |
| 586 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE); | 674 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE); |
| 587 // TODO(sfiera): notify only when a category changed above. | 675 // TODO(sfiera): notify only when a category changed above. |
| 588 NotifyNewSuggestions(category); | 676 NotifyNewSuggestionsOrInvokeCallback(category, fetched_more_callback); |
| 589 } | 677 } |
| 590 | 678 |
| 591 // TODO(sfiera): equivalent metrics for non-articles. | 679 // TODO(sfiera): equivalent metrics for non-articles. |
| 592 const CategoryContent& content = categories_[articles_category_]; | 680 const CategoryContent& content = categories_[articles_category_]; |
| 593 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles", | 681 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles", |
| 594 content.snippets.size()); | 682 content.snippets.size()); |
| 595 if (content.snippets.empty() && !content.dismissed.empty()) { | 683 if (content.snippets.empty() && !content.dismissed.empty()) { |
| 596 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded", | 684 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded", |
| 597 content.dismissed.size()); | 685 content.dismissed.size()); |
| 598 } | 686 } |
| 599 | 687 |
| 600 // Reschedule after a successful fetch. This resets all currently scheduled | 688 // Reschedule after a successful fetch. This resets all currently scheduled |
| 601 // fetches, to make sure the fallback interval triggers only if no wifi fetch | 689 // fetches, to make sure the fallback interval triggers only if no wifi fetch |
| 602 // succeeded, and also that we don't do a background fetch immediately after | 690 // succeeded, and also that we don't do a background fetch immediately after |
| 603 // a user-initiated one. | 691 // a user-initiated one. |
| 604 if (fetched_categories) | 692 if (fetched_categories) |
| 605 RescheduleFetching(true); | 693 RescheduleFetching(true); |
| 606 } | 694 } |
| 607 | 695 |
| 608 void NTPSnippetsService::ArchiveSnippets(Category category, | 696 void NTPSnippetsService::IncludeSnippets(const Category& category, |
| 609 NTPSnippet::PtrVector* to_archive) { | 697 NTPSnippet::PtrVector new_snippets, |
| 610 CategoryContent* content = &categories_[category]; | 698 bool replace_snippets) { |
| 611 database_->DeleteSnippets(GetSnippetIDVector(*to_archive)); | |
| 612 // Do not delete the thumbnail images as they are still handy on open NTPs. | |
| 613 | |
| 614 // Archive previous snippets - move them at the beginning of the list. | |
| 615 content->archived.insert(content->archived.begin(), | |
| 616 std::make_move_iterator(to_archive->begin()), | |
| 617 std::make_move_iterator(to_archive->end())); | |
| 618 RemoveNullPointers(to_archive); | |
| 619 | |
| 620 // If there are more archived snippets than we want to keep, delete the | |
| 621 // oldest ones by their fetch time (which are always in the back). | |
| 622 if (content->archived.size() > kMaxArchivedSnippetCount) { | |
| 623 NTPSnippet::PtrVector to_delete( | |
| 624 std::make_move_iterator(content->archived.begin() + | |
| 625 kMaxArchivedSnippetCount), | |
| 626 std::make_move_iterator(content->archived.end())); | |
| 627 content->archived.resize(kMaxArchivedSnippetCount); | |
| 628 database_->DeleteImages(GetSnippetIDVector(to_delete)); | |
| 629 } | |
| 630 } | |
| 631 | |
| 632 void NTPSnippetsService::ReplaceSnippets(Category category, | |
| 633 NTPSnippet::PtrVector new_snippets) { | |
| 634 DCHECK(ready()); | 699 DCHECK(ready()); |
| 635 CategoryContent* content = &categories_[category]; | 700 CategoryContent* content = &categories_[category]; |
| 636 | 701 |
| 637 // Remove new snippets that have been dismissed. | 702 // Remove new snippets that have been dismissed. |
| 638 EraseMatchingSnippets(&new_snippets, content->dismissed); | 703 EraseMatchingSnippets(&new_snippets, content->dismissed); |
| 639 | 704 |
| 640 // Fill in default publish/expiry dates where required. | 705 AssignExpiryAndPublishDates(&new_snippets); |
| 641 for (std::unique_ptr<NTPSnippet>& snippet : new_snippets) { | 706 RemoveIncompleteSnippets(&new_snippets); |
| 642 if (snippet->publish_date().is_null()) | |
| 643 snippet->set_publish_date(base::Time::Now()); | |
| 644 if (snippet->expiry_date().is_null()) { | |
| 645 snippet->set_expiry_date( | |
| 646 snippet->publish_date() + | |
| 647 base::TimeDelta::FromMinutes(kDefaultExpiryTimeMins)); | |
| 648 } | |
| 649 } | |
| 650 | |
| 651 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 652 switches::kAddIncompleteSnippets)) { | |
| 653 int num_new_snippets = new_snippets.size(); | |
| 654 // Remove snippets that do not have all the info we need to display it to | |
| 655 // the user. | |
| 656 new_snippets.erase( | |
| 657 std::remove_if(new_snippets.begin(), new_snippets.end(), | |
| 658 [](const std::unique_ptr<NTPSnippet>& snippet) { | |
| 659 return !snippet->is_complete(); | |
| 660 }), | |
| 661 new_snippets.end()); | |
| 662 int num_snippets_dismissed = num_new_snippets - new_snippets.size(); | |
| 663 UMA_HISTOGRAM_BOOLEAN("NewTabPage.Snippets.IncompleteSnippetsAfterFetch", | |
| 664 num_snippets_dismissed > 0); | |
| 665 if (num_snippets_dismissed > 0) { | |
| 666 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumIncompleteSnippets", | |
| 667 num_snippets_dismissed); | |
| 668 } | |
| 669 } | |
| 670 | 707 |
| 671 // Do not touch the current set of snippets if the newly fetched one is empty. | 708 // Do not touch the current set of snippets if the newly fetched one is empty. |
| 672 if (new_snippets.empty()) | 709 if (new_snippets.empty()) |
| 673 return; | 710 return; |
| 674 | 711 |
| 675 // It's entirely possible that the newly fetched snippets contain articles | 712 // It's entirely possible that the newly fetched snippets contain articles |
| 676 // that have been present before. | 713 // that have been present before. |
| 677 // Since archival removes snippets from the database (indexed by | 714 // Since archival removes snippets from the database (indexed by |
| 678 // snippet->id()), we need to make sure to only archive snippets that don't | 715 // snippet->id()), we need to make sure to only archive snippets that don't |
| 679 // appear with the same ID in the new suggestions (it's fine for additional | 716 // appear with the same ID in the new suggestions (it's fine for additional |
| 680 // IDs though). | 717 // IDs though). |
| 681 EraseByPrimaryID(&content->snippets, *GetSnippetIDVector(new_snippets)); | 718 EraseByPrimaryID(&content->snippets, *GetSnippetIDVector(new_snippets)); |
| 682 ArchiveSnippets(category, &content->snippets); | |
| 683 | 719 |
| 684 // Save new articles to the DB. | 720 SaveSnippets(category, std::move(new_snippets), replace_snippets); |
| 721 } | |
| 722 | |
| 723 void NTPSnippetsService::SaveSnippets(const Category& category, | |
| 724 NTPSnippet::PtrVector new_snippets, | |
| 725 bool replace_snippets) { | |
| 685 database_->SaveSnippets(new_snippets); | 726 database_->SaveSnippets(new_snippets); |
| 686 | 727 |
| 687 content->snippets = std::move(new_snippets); | 728 CategoryContent* content = &categories_[category]; |
| 729 | |
| 730 if (replace_snippets) { | |
| 731 ArchiveSnippets(category, &content->snippets); | |
| 732 content->snippets = std::move(new_snippets); | |
| 733 return; | |
| 734 } | |
| 735 | |
| 736 content->snippets.insert(content->snippets.end(), | |
| 737 std::make_move_iterator(new_snippets.begin()), | |
| 738 std::make_move_iterator(new_snippets.end())); | |
| 688 } | 739 } |
| 689 | 740 |
| 741 void NTPSnippetsService::ArchiveSnippets(Category category, | |
| 742 NTPSnippet::PtrVector* to_archive) { | |
| 743 CategoryContent* content = &categories_[category]; | |
| 744 database_->DeleteSnippets(GetSnippetIDVector(*to_archive)); | |
| 745 // Do not delete the thumbnail images as they are still handy on open NTPs. | |
| 746 | |
| 747 // Archive previous snippets - move them at the beginning of the list. | |
| 748 content->archived.insert(content->archived.begin(), | |
| 749 std::make_move_iterator(to_archive->begin()), | |
| 750 std::make_move_iterator(to_archive->end())); | |
| 751 RemoveNullPointers(to_archive); | |
| 752 | |
| 753 // If there are more archived snippets than we want to keep, delete the | |
| 754 // oldest ones by their fetch time (which are always in the back). | |
| 755 if (content->archived.size() > kMaxArchivedSnippetCount) { | |
| 756 NTPSnippet::PtrVector to_delete( | |
| 757 std::make_move_iterator(content->archived.begin() + | |
| 758 kMaxArchivedSnippetCount), | |
| 759 std::make_move_iterator(content->archived.end())); | |
| 760 content->archived.resize(kMaxArchivedSnippetCount); | |
| 761 database_->DeleteImages(GetSnippetIDVector(to_delete)); | |
| 762 } | |
| 763 } | |
| 690 void NTPSnippetsService::ClearExpiredDismissedSnippets() { | 764 void NTPSnippetsService::ClearExpiredDismissedSnippets() { |
| 691 std::vector<Category> categories_to_erase; | 765 std::vector<Category> categories_to_erase; |
| 692 | 766 |
| 693 const base::Time now = base::Time::Now(); | 767 const base::Time now = base::Time::Now(); |
| 694 | 768 |
| 695 for (auto& item : categories_) { | 769 for (auto& item : categories_) { |
| 696 Category category = item.first; | 770 Category category = item.first; |
| 697 CategoryContent* content = &item.second; | 771 CategoryContent* content = &item.second; |
| 698 | 772 |
| 699 NTPSnippet::PtrVector to_delete; | 773 NTPSnippet::PtrVector to_delete; |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 863 } | 937 } |
| 864 | 938 |
| 865 void NTPSnippetsService::FinishInitialization() { | 939 void NTPSnippetsService::FinishInitialization() { |
| 866 if (nuke_when_initialized_) { | 940 if (nuke_when_initialized_) { |
| 867 // We nuke here in addition to EnterStateReady, so that it happens even if | 941 // We nuke here in addition to EnterStateReady, so that it happens even if |
| 868 // we enter the DISABLED state below. | 942 // we enter the DISABLED state below. |
| 869 NukeAllSnippets(); | 943 NukeAllSnippets(); |
| 870 nuke_when_initialized_ = false; | 944 nuke_when_initialized_ = false; |
| 871 } | 945 } |
| 872 | 946 |
| 873 snippets_fetcher_->SetCallback( | |
| 874 base::Bind(&NTPSnippetsService::OnFetchFinished, base::Unretained(this))); | |
| 875 | |
| 876 // |image_fetcher_| can be null in tests. | 947 // |image_fetcher_| can be null in tests. |
| 877 if (image_fetcher_) { | 948 if (image_fetcher_) { |
| 878 image_fetcher_->SetImageFetcherDelegate(this); | 949 image_fetcher_->SetImageFetcherDelegate(this); |
| 879 image_fetcher_->SetDataUseServiceName( | 950 image_fetcher_->SetDataUseServiceName( |
| 880 data_use_measurement::DataUseUserData::NTP_SNIPPETS); | 951 data_use_measurement::DataUseUserData::NTP_SNIPPETS); |
| 881 } | 952 } |
| 882 | 953 |
| 883 // Note: Initializing the status service will run the callback right away with | 954 // Note: Initializing the status service will run the callback right away with |
| 884 // the current state. | 955 // the current state. |
| 885 snippets_status_service_->Init(base::Bind( | 956 snippets_status_service_->Init(base::Bind( |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 966 state_ = State::ERROR_OCCURRED; | 1037 state_ = State::ERROR_OCCURRED; |
| 967 EnterStateError(); | 1038 EnterStateError(); |
| 968 break; | 1039 break; |
| 969 } | 1040 } |
| 970 | 1041 |
| 971 // Schedule or un-schedule background fetching after each state change. | 1042 // Schedule or un-schedule background fetching after each state change. |
| 972 RescheduleFetching(false); | 1043 RescheduleFetching(false); |
| 973 } | 1044 } |
| 974 | 1045 |
| 975 void NTPSnippetsService::NotifyNewSuggestions(Category category) { | 1046 void NTPSnippetsService::NotifyNewSuggestions(Category category) { |
| 1047 NotifyNewSuggestionsOrInvokeCallback(category, NullCallback()); | |
| 1048 } | |
| 1049 | |
| 1050 void NTPSnippetsService::NotifyNewSuggestionsOrInvokeCallback( | |
| 1051 Category category, | |
| 1052 FetchedMoreCallback fetched_more_callback) { | |
| 976 DCHECK(base::ContainsKey(categories_, category)); | 1053 DCHECK(base::ContainsKey(categories_, category)); |
| 977 const CategoryContent& content = categories_[category]; | 1054 const CategoryContent& content = categories_[category]; |
| 978 DCHECK(IsCategoryStatusAvailable(content.status)); | 1055 DCHECK(IsCategoryStatusAvailable(content.status)); |
| 979 | |
| 980 std::vector<ContentSuggestion> result; | 1056 std::vector<ContentSuggestion> result; |
| 981 for (const std::unique_ptr<NTPSnippet>& snippet : content.snippets) { | 1057 for (const std::unique_ptr<NTPSnippet>& snippet : content.snippets) { |
| 982 // TODO(sfiera): if a snippet is not going to be displayed, move it | 1058 // TODO(sfiera): if a snippet is not going to be displayed, move it |
| 983 // directly to content.dismissed on fetch. Otherwise, we might prune | 1059 // directly to content.dismissed on fetch. Otherwise, we might prune |
| 984 // other snippets to get down to kMaxSnippetCount, only to hide one of the | 1060 // other snippets to get down to kMaxSnippetCount, only to hide one of the |
| 985 // incomplete ones we kept. | 1061 // incomplete ones we kept. |
| 986 if (!snippet->is_complete()) | 1062 if (!snippet->is_complete()) |
| 987 continue; | 1063 continue; |
| 988 ContentSuggestion suggestion(category, snippet->id(), | 1064 result.emplace_back( |
| 989 snippet->best_source().url); | 1065 ContentSuggestion::FromSnippet(category, snippet.get())); |
| 990 suggestion.set_amp_url(snippet->best_source().amp_url); | |
| 991 suggestion.set_title(base::UTF8ToUTF16(snippet->title())); | |
| 992 suggestion.set_snippet_text(base::UTF8ToUTF16(snippet->snippet())); | |
| 993 suggestion.set_publish_date(snippet->publish_date()); | |
| 994 suggestion.set_publisher_name( | |
| 995 base::UTF8ToUTF16(snippet->best_source().publisher_name)); | |
| 996 suggestion.set_score(snippet->score()); | |
| 997 result.emplace_back(std::move(suggestion)); | |
| 998 } | 1066 } |
| 999 | 1067 |
| 1000 DVLOG(1) << "NotifyNewSuggestions(" << category << "): " << result.size() | 1068 DVLOG(1) << "NotifyNewSuggestions(" << category << "): " << result.size() |
| 1001 << " items."; | 1069 << " items."; |
| 1002 observer()->OnNewSuggestions(this, category, std::move(result)); | 1070 if (fetched_more_callback.is_null()) { |
| 1071 observer()->OnNewSuggestions(this, category, std::move(result)); | |
| 1072 } else { | |
| 1073 fetched_more_callback.Run(std::move(result)); | |
| 1074 } | |
| 1003 } | 1075 } |
| 1004 | 1076 |
| 1005 void NTPSnippetsService::UpdateCategoryStatus(Category category, | 1077 void NTPSnippetsService::UpdateCategoryStatus(Category category, |
| 1006 CategoryStatus status) { | 1078 CategoryStatus status) { |
| 1007 DCHECK(base::ContainsKey(categories_, category)); | 1079 DCHECK(base::ContainsKey(categories_, category)); |
| 1008 CategoryContent& content = categories_[category]; | 1080 CategoryContent& content = categories_[category]; |
| 1009 if (status == content.status) | 1081 if (status == content.status) |
| 1010 return; | 1082 return; |
| 1011 | 1083 |
| 1012 DVLOG(1) << "UpdateCategoryStatus(): " << category.id() << ": " | 1084 DVLOG(1) << "UpdateCategoryStatus(): " << category.id() << ": " |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1112 } | 1184 } |
| 1113 | 1185 |
| 1114 NTPSnippetsService::CategoryContent::CategoryContent() = default; | 1186 NTPSnippetsService::CategoryContent::CategoryContent() = default; |
| 1115 NTPSnippetsService::CategoryContent::CategoryContent(CategoryContent&&) = | 1187 NTPSnippetsService::CategoryContent::CategoryContent(CategoryContent&&) = |
| 1116 default; | 1188 default; |
| 1117 NTPSnippetsService::CategoryContent::~CategoryContent() = default; | 1189 NTPSnippetsService::CategoryContent::~CategoryContent() = default; |
| 1118 NTPSnippetsService::CategoryContent& NTPSnippetsService::CategoryContent:: | 1190 NTPSnippetsService::CategoryContent& NTPSnippetsService::CategoryContent:: |
| 1119 operator=(CategoryContent&&) = default; | 1191 operator=(CategoryContent&&) = default; |
| 1120 | 1192 |
| 1121 } // namespace ntp_snippets | 1193 } // namespace ntp_snippets |
| OLD | NEW |