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

Side by Side Diff: chrome/browser/ntp_snippets/download_suggestions_provider.cc

Issue 2673633002: [NTP::Downloads] Do not show old downloads. (Closed)
Patch Set: comments + clean rebase (sorry). Created 3 years, 10 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
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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/ntp_snippets/download_suggestions_provider.h" 5 #include "chrome/browser/ntp_snippets/download_suggestions_provider.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/feature_list.h" 11 #include "base/feature_list.h"
12 #include "base/guid.h" 12 #include "base/guid.h"
13 #include "base/memory/ptr_util.h" 13 #include "base/memory/ptr_util.h"
14 #include "base/stl_util.h" 14 #include "base/stl_util.h"
15 #include "base/strings/string_number_conversions.h" 15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_util.h" 16 #include "base/strings/string_util.h"
17 #include "base/strings/utf_string_conversions.h" 17 #include "base/strings/utf_string_conversions.h"
18 #include "base/threading/thread_task_runner_handle.h" 18 #include "base/threading/thread_task_runner_handle.h"
19 #include "base/time/clock.h"
19 #include "base/time/time.h" 20 #include "base/time/time.h"
20 #include "chrome/common/chrome_features.h" 21 #include "chrome/common/chrome_features.h"
21 #include "chrome/grit/generated_resources.h" 22 #include "chrome/grit/generated_resources.h"
22 #include "components/ntp_snippets/features.h" 23 #include "components/ntp_snippets/features.h"
23 #include "components/ntp_snippets/pref_names.h" 24 #include "components/ntp_snippets/pref_names.h"
24 #include "components/ntp_snippets/pref_util.h" 25 #include "components/ntp_snippets/pref_util.h"
25 #include "components/offline_pages/core/offline_page_model_query.h" 26 #include "components/offline_pages/core/offline_page_model_query.h"
26 #include "components/prefs/pref_registry_simple.h" 27 #include "components/prefs/pref_registry_simple.h"
27 #include "components/prefs/pref_service.h" 28 #include "components/prefs/pref_service.h"
28 #include "components/variations/variations_associated_data.h" 29 #include "components/variations/variations_associated_data.h"
29 #include "ui/base/l10n/l10n_util.h" 30 #include "ui/base/l10n/l10n_util.h"
30 #include "ui/gfx/image/image.h" 31 #include "ui/gfx/image/image.h"
31 32
32 using content::DownloadItem; 33 using content::DownloadItem;
33 using content::DownloadManager; 34 using content::DownloadManager;
34 using ntp_snippets::Category; 35 using ntp_snippets::Category;
35 using ntp_snippets::CategoryInfo; 36 using ntp_snippets::CategoryInfo;
36 using ntp_snippets::CategoryStatus; 37 using ntp_snippets::CategoryStatus;
37 using ntp_snippets::ContentSuggestion; 38 using ntp_snippets::ContentSuggestion;
38 using ntp_snippets::prefs::kDismissedAssetDownloadSuggestions; 39 using ntp_snippets::prefs::kDismissedAssetDownloadSuggestions;
39 using ntp_snippets::prefs::kDismissedOfflinePageDownloadSuggestions; 40 using ntp_snippets::prefs::kDismissedOfflinePageDownloadSuggestions;
40 using offline_pages::OfflinePageItem; 41 using offline_pages::OfflinePageItem;
41 using offline_pages::OfflinePageModelQuery; 42 using offline_pages::OfflinePageModelQuery;
42 using offline_pages::OfflinePageModelQueryBuilder; 43 using offline_pages::OfflinePageModelQueryBuilder;
43 44
44 namespace { 45 namespace {
45 46
46 const int kDefaultMaxSuggestionsCount = 5; 47 const int kDefaultMaxSuggestionsCount = 5;
48 const int kDefaultMaxDownloadAgeHours = 6 * 7 * 24; // 6 weeks
47 const char kAssetDownloadsPrefix = 'D'; 49 const char kAssetDownloadsPrefix = 'D';
48 const char kOfflinePageDownloadsPrefix = 'O'; 50 const char kOfflinePageDownloadsPrefix = 'O';
49 51
52 // NOTE: You must set variation param values for both features (one of them may
53 // be disabled in future).
50 const char* kMaxSuggestionsCountParamName = "downloads_max_count"; 54 const char* kMaxSuggestionsCountParamName = "downloads_max_count";
55 const char* kMaxDownloadAgeHoursParamName = "downloads_max_age_hours";
51 56
52 bool CompareOfflinePagesMostRecentlyCreatedFirst(const OfflinePageItem& left, 57 const base::Feature& GetEnabledDownloadsFeature() {
53 const OfflinePageItem& right) { 58 bool assets_enabled =
54 return left.creation_time > right.creation_time; 59 base::FeatureList::IsEnabled(features::kAssetDownloadSuggestionsFeature);
60 DCHECK(assets_enabled ||
61 base::FeatureList::IsEnabled(
62 features::kOfflinePageDownloadSuggestionsFeature));
63 return assets_enabled ? features::kAssetDownloadSuggestionsFeature
64 : features::kOfflinePageDownloadSuggestionsFeature;
55 } 65 }
56 66
57 int GetMaxSuggestionsCount() { 67 int GetMaxSuggestionsCount() {
58 bool assets_enabled = 68 // One cannot get a variation param from a disabled feature, so the enabled
59 base::FeatureList::IsEnabled(features::kAssetDownloadSuggestionsFeature); 69 // one is taken.
60 return variations::GetVariationParamByFeatureAsInt( 70 return variations::GetVariationParamByFeatureAsInt(
61 assets_enabled ? features::kAssetDownloadSuggestionsFeature 71 GetEnabledDownloadsFeature(), kMaxSuggestionsCountParamName,
62 : features::kOfflinePageDownloadSuggestionsFeature, 72 kDefaultMaxSuggestionsCount);
63 kMaxSuggestionsCountParamName, kDefaultMaxSuggestionsCount); 73 }
74
75 int GetMaxDownloadAgeHours() {
76 // One cannot get a variation param from a disabled feature, so the enabled
77 // one is taken.
78 return variations::GetVariationParamByFeatureAsInt(
79 GetEnabledDownloadsFeature(), kMaxDownloadAgeHoursParamName,
80 kDefaultMaxDownloadAgeHours);
81 }
82
83 base::Time GetOfflinePagePublishedTime(const OfflinePageItem& item) {
84 return item.creation_time;
85 }
86
87 bool CompareOfflinePagesMostRecentlyPublishedFirst(
88 const OfflinePageItem& left,
89 const OfflinePageItem& right) {
90 return GetOfflinePagePublishedTime(left) > GetOfflinePagePublishedTime(right);
64 } 91 }
65 92
66 std::string GetOfflinePagePerCategoryID(int64_t raw_offline_page_id) { 93 std::string GetOfflinePagePerCategoryID(int64_t raw_offline_page_id) {
67 // Raw ID is prefixed in order to avoid conflicts with asset downloads. 94 // Raw ID is prefixed in order to avoid conflicts with asset downloads.
68 return std::string(1, kOfflinePageDownloadsPrefix) + 95 return std::string(1, kOfflinePageDownloadsPrefix) +
69 base::IntToString(raw_offline_page_id); 96 base::IntToString(raw_offline_page_id);
70 } 97 }
71 98
72 std::string GetAssetDownloadPerCategoryID(uint32_t raw_download_id) { 99 std::string GetAssetDownloadPerCategoryID(uint32_t raw_download_id) {
73 // Raw ID is prefixed in order to avoid conflicts with offline page downloads. 100 // Raw ID is prefixed in order to avoid conflicts with offline page downloads.
(...skipping 10 matching lines...) Expand all
84 return true; 111 return true;
85 } 112 }
86 if (id_within_category[0] == kAssetDownloadsPrefix) { 113 if (id_within_category[0] == kAssetDownloadsPrefix) {
87 return false; 114 return false;
88 } 115 }
89 } 116 }
90 NOTREACHED() << "Unknown id_within_category " << id_within_category; 117 NOTREACHED() << "Unknown id_within_category " << id_within_category;
91 return false; 118 return false;
92 } 119 }
93 120
94 bool IsDownloadCompleted(const DownloadItem& item) { 121 bool IsAssetDownloadCompleted(const DownloadItem& item) {
95 return item.GetState() == DownloadItem::DownloadState::COMPLETE && 122 return item.GetState() == DownloadItem::DownloadState::COMPLETE &&
96 !item.GetFileExternallyRemoved(); 123 !item.GetFileExternallyRemoved();
97 } 124 }
98 125
99 base::Time GetAssetDownloadPublishedTime(const DownloadItem& item) { 126 base::Time GetAssetDownloadPublishedTime(const DownloadItem& item) {
100 return item.GetStartTime(); 127 return item.GetStartTime();
101 } 128 }
102 129
103 bool CompareDownloadsMostRecentlyDownloadedFirst(const DownloadItem* left, 130 bool CompareDownloadsMostRecentlyPublishedFirst(const DownloadItem* left,
104 const DownloadItem* right) { 131 const DownloadItem* right) {
105 return GetAssetDownloadPublishedTime(*left) > 132 return GetAssetDownloadPublishedTime(*left) >
106 GetAssetDownloadPublishedTime(*right); 133 GetAssetDownloadPublishedTime(*right);
107 } 134 }
108 135
109 bool IsClientIdForOfflinePageDownload( 136 bool IsClientIdForOfflinePageDownload(
110 offline_pages::ClientPolicyController* policy_controller, 137 offline_pages::ClientPolicyController* policy_controller,
111 const offline_pages::ClientId& client_id) { 138 const offline_pages::ClientId& client_id) {
112 return policy_controller->IsSupportedByDownload(client_id.name_space); 139 return policy_controller->IsSupportedByDownload(client_id.name_space);
113 } 140 }
114 141
115 std::unique_ptr<OfflinePageModelQuery> BuildOfflinePageDownloadsQuery( 142 std::unique_ptr<OfflinePageModelQuery> BuildOfflinePageDownloadsQuery(
116 offline_pages::OfflinePageModel* model) { 143 offline_pages::OfflinePageModel* model) {
117 OfflinePageModelQueryBuilder builder; 144 OfflinePageModelQueryBuilder builder;
118 builder.RequireSupportedByDownload( 145 builder.RequireSupportedByDownload(
119 OfflinePageModelQuery::Requirement::INCLUDE_MATCHING); 146 OfflinePageModelQuery::Requirement::INCLUDE_MATCHING);
120 return builder.Build(model->GetPolicyController()); 147 return builder.Build(model->GetPolicyController());
121 } 148 }
122 149
123 } // namespace 150 } // namespace
124 151
125 DownloadSuggestionsProvider::DownloadSuggestionsProvider( 152 DownloadSuggestionsProvider::DownloadSuggestionsProvider(
126 ContentSuggestionsProvider::Observer* observer, 153 ContentSuggestionsProvider::Observer* observer,
127 offline_pages::OfflinePageModel* offline_page_model, 154 offline_pages::OfflinePageModel* offline_page_model,
128 content::DownloadManager* download_manager, 155 content::DownloadManager* download_manager,
129 DownloadHistory* download_history, 156 DownloadHistory* download_history,
130 PrefService* pref_service) 157 PrefService* pref_service,
158 std::unique_ptr<base::Clock> clock)
131 : ContentSuggestionsProvider(observer), 159 : ContentSuggestionsProvider(observer),
132 category_status_(CategoryStatus::AVAILABLE_LOADING), 160 category_status_(CategoryStatus::AVAILABLE_LOADING),
133 provided_category_(Category::FromKnownCategory( 161 provided_category_(Category::FromKnownCategory(
134 ntp_snippets::KnownCategories::DOWNLOADS)), 162 ntp_snippets::KnownCategories::DOWNLOADS)),
135 offline_page_model_(offline_page_model), 163 offline_page_model_(offline_page_model),
136 download_manager_(download_manager), 164 download_manager_(download_manager),
137 download_history_(download_history), 165 download_history_(download_history),
138 pref_service_(pref_service), 166 pref_service_(pref_service),
167 clock_(std::move(clock)),
139 is_asset_downloads_initialization_complete_(false), 168 is_asset_downloads_initialization_complete_(false),
140 weak_ptr_factory_(this) { 169 weak_ptr_factory_(this) {
141 observer->OnCategoryStatusChanged(this, provided_category_, category_status_); 170 observer->OnCategoryStatusChanged(this, provided_category_, category_status_);
142 171
143 DCHECK(offline_page_model_ || download_manager_); 172 DCHECK(offline_page_model_ || download_manager_);
144 if (offline_page_model_) { 173 if (offline_page_model_) {
145 offline_page_model_->AddObserver(this); 174 offline_page_model_->AddObserver(this);
146 } 175 }
147 176
148 if (download_manager_) { 177 if (download_manager_) {
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 0U); 369 0U);
341 370
342 int max_suggestions_count = GetMaxSuggestionsCount(); 371 int max_suggestions_count = GetMaxSuggestionsCount();
343 if (static_cast<int>(cached_offline_page_downloads_.size()) < 372 if (static_cast<int>(cached_offline_page_downloads_.size()) <
344 max_suggestions_count) { 373 max_suggestions_count) {
345 cached_offline_page_downloads_.push_back(added_page); 374 cached_offline_page_downloads_.push_back(added_page);
346 } else if (max_suggestions_count > 0) { 375 } else if (max_suggestions_count > 0) {
347 auto oldest_page_iterator = 376 auto oldest_page_iterator =
348 std::max_element(cached_offline_page_downloads_.begin(), 377 std::max_element(cached_offline_page_downloads_.begin(),
349 cached_offline_page_downloads_.end(), 378 cached_offline_page_downloads_.end(),
350 &CompareOfflinePagesMostRecentlyCreatedFirst); 379 &CompareOfflinePagesMostRecentlyPublishedFirst);
351 *oldest_page_iterator = added_page; 380 *oldest_page_iterator = added_page;
352 } 381 }
353 382
354 SubmitContentSuggestions(); 383 SubmitContentSuggestions();
355 } 384 }
356 385
357 void DownloadSuggestionsProvider::OfflinePageDeleted( 386 void DownloadSuggestionsProvider::OfflinePageDeleted(
358 int64_t offline_id, 387 int64_t offline_id,
359 const offline_pages::ClientId& client_id) { 388 const offline_pages::ClientId& client_id) {
360 DCHECK(offline_page_model_); 389 DCHECK(offline_page_model_);
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
413 // we may need to retrieve all downloads, but |OnDownloadRemoved| is called 442 // we may need to retrieve all downloads, but |OnDownloadRemoved| is called
414 // before the download is removed from the list. 443 // before the download is removed from the list.
415 } 444 }
416 445
417 void DownloadSuggestionsProvider::OnDownloadDestroyed( 446 void DownloadSuggestionsProvider::OnDownloadDestroyed(
418 content::DownloadItem* item) { 447 content::DownloadItem* item) {
419 DCHECK(is_asset_downloads_initialization_complete_); 448 DCHECK(is_asset_downloads_initialization_complete_);
420 449
421 item->RemoveObserver(this); 450 item->RemoveObserver(this);
422 451
423 if (!IsDownloadCompleted(*item)) { 452 if (!IsAssetDownloadCompleted(*item)) {
424 return; 453 return;
425 } 454 }
426 // TODO(vitaliii): Implement a better way to clean up dismissed IDs (in case 455 // TODO(vitaliii): Implement a better way to clean up dismissed IDs (in case
427 // some calls are missed). 456 // some calls are missed).
428 InvalidateSuggestion(GetAssetDownloadPerCategoryID(item->GetId())); 457 InvalidateSuggestion(GetAssetDownloadPerCategoryID(item->GetId()));
429 } 458 }
430 459
431 void DownloadSuggestionsProvider::OnHistoryQueryComplete() { 460 void DownloadSuggestionsProvider::OnHistoryQueryComplete() {
432 is_asset_downloads_initialization_complete_ = true; 461 is_asset_downloads_initialization_complete_ = true;
433 if (download_manager_) { 462 if (download_manager_) {
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
487 std::vector<DownloadItem*> all_downloads; 516 std::vector<DownloadItem*> all_downloads;
488 download_manager_->GetAllDownloads(&all_downloads); 517 download_manager_->GetAllDownloads(&all_downloads);
489 std::set<std::string> old_dismissed_ids = ReadAssetDismissedIDsFromPrefs(); 518 std::set<std::string> old_dismissed_ids = ReadAssetDismissedIDsFromPrefs();
490 std::set<std::string> retained_dismissed_ids; 519 std::set<std::string> retained_dismissed_ids;
491 cached_asset_downloads_.clear(); 520 cached_asset_downloads_.clear();
492 for (DownloadItem* item : all_downloads) { 521 for (DownloadItem* item : all_downloads) {
493 std::string within_category_id = 522 std::string within_category_id =
494 GetAssetDownloadPerCategoryID(item->GetId()); 523 GetAssetDownloadPerCategoryID(item->GetId());
495 if (old_dismissed_ids.count(within_category_id)) { 524 if (old_dismissed_ids.count(within_category_id)) {
496 retained_dismissed_ids.insert(within_category_id); 525 retained_dismissed_ids.insert(within_category_id);
497 } else if (IsDownloadCompleted(*item)) { 526 } else if (IsAssetDownloadCompleted(*item) &&
527 !IsDownloadOutdated(GetAssetDownloadPublishedTime(*item))) {
498 cached_asset_downloads_.push_back(item); 528 cached_asset_downloads_.push_back(item);
499 // We may already observe this item and, therefore, we remove the 529 // We may already observe this item and, therefore, we remove the
500 // observer first. 530 // observer first.
501 item->RemoveObserver(this); 531 item->RemoveObserver(this);
502 item->AddObserver(this); 532 item->AddObserver(this);
503 } 533 }
504 } 534 }
505 535
506 if (old_dismissed_ids.size() != retained_dismissed_ids.size()) { 536 if (old_dismissed_ids.size() != retained_dismissed_ids.size()) {
507 StoreAssetDismissedIDsToPrefs(retained_dismissed_ids); 537 StoreAssetDismissedIDsToPrefs(retained_dismissed_ids);
508 } 538 }
509 539
510 const int max_suggestions_count = GetMaxSuggestionsCount(); 540 const int max_suggestions_count = GetMaxSuggestionsCount();
511 if (static_cast<int>(cached_asset_downloads_.size()) > 541 if (static_cast<int>(cached_asset_downloads_.size()) >
512 max_suggestions_count) { 542 max_suggestions_count) {
513 // Partially sorts |downloads| such that: 543 // Partially sorts |downloads| such that:
514 // 1) The element at the index |max_suggestions_count| is changed to the 544 // 1) The element at the index |max_suggestions_count| is changed to the
515 // element which would occur on this position if |downloads| was sorted; 545 // element which would occur on this position if |downloads| was sorted;
516 // 2) All of the elements before index |max_suggestions_count| are less than 546 // 2) All of the elements before index |max_suggestions_count| are less than
517 // or equal to the elements after it. 547 // or equal to the elements after it.
518 std::nth_element(cached_asset_downloads_.begin(), 548 std::nth_element(cached_asset_downloads_.begin(),
519 cached_asset_downloads_.begin() + max_suggestions_count, 549 cached_asset_downloads_.begin() + max_suggestions_count,
520 cached_asset_downloads_.end(), 550 cached_asset_downloads_.end(),
521 &CompareDownloadsMostRecentlyDownloadedFirst); 551 &CompareDownloadsMostRecentlyPublishedFirst);
522 cached_asset_downloads_.resize(max_suggestions_count); 552 cached_asset_downloads_.resize(max_suggestions_count);
523 } 553 }
524 } 554 }
525 555
526 void DownloadSuggestionsProvider:: 556 void DownloadSuggestionsProvider::
527 AsynchronouslyFetchAllDownloadsAndSubmitSuggestions() { 557 AsynchronouslyFetchAllDownloadsAndSubmitSuggestions() {
528 FetchAssetsDownloads(); 558 FetchAssetsDownloads();
529 AsynchronouslyFetchOfflinePagesDownloads(/*notify=*/true); 559 AsynchronouslyFetchOfflinePagesDownloads(/*notify=*/true);
530 } 560 }
531 561
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
563 offline_page.offline_id)), 593 offline_page.offline_id)),
564 offline_page.url); 594 offline_page.url);
565 595
566 if (offline_page.title.empty()) { 596 if (offline_page.title.empty()) {
567 // TODO(vitaliii): Remove this fallback once the OfflinePageModel provides 597 // TODO(vitaliii): Remove this fallback once the OfflinePageModel provides
568 // titles for all (relevant) OfflinePageItems. 598 // titles for all (relevant) OfflinePageItems.
569 suggestion.set_title(base::UTF8ToUTF16(offline_page.url.spec())); 599 suggestion.set_title(base::UTF8ToUTF16(offline_page.url.spec()));
570 } else { 600 } else {
571 suggestion.set_title(offline_page.title); 601 suggestion.set_title(offline_page.title);
572 } 602 }
573 suggestion.set_publish_date(offline_page.creation_time); 603 suggestion.set_publish_date(GetOfflinePagePublishedTime(offline_page));
574 suggestion.set_publisher_name(base::UTF8ToUTF16(offline_page.url.host())); 604 suggestion.set_publisher_name(base::UTF8ToUTF16(offline_page.url.host()));
575 auto extra = base::MakeUnique<ntp_snippets::DownloadSuggestionExtra>(); 605 auto extra = base::MakeUnique<ntp_snippets::DownloadSuggestionExtra>();
576 extra->is_download_asset = false; 606 extra->is_download_asset = false;
577 extra->offline_page_id = offline_page.offline_id; 607 extra->offline_page_id = offline_page.offline_id;
578 suggestion.set_download_suggestion_extra(std::move(extra)); 608 suggestion.set_download_suggestion_extra(std::move(extra));
579 return suggestion; 609 return suggestion;
580 } 610 }
581 611
582 ContentSuggestion DownloadSuggestionsProvider::ConvertDownloadItem( 612 ContentSuggestion DownloadSuggestionsProvider::ConvertDownloadItem(
583 const DownloadItem& download_item) const { 613 const DownloadItem& download_item) const {
584 ContentSuggestion suggestion( 614 ContentSuggestion suggestion(
585 ContentSuggestion::ID(provided_category_, GetAssetDownloadPerCategoryID( 615 ContentSuggestion::ID(provided_category_, GetAssetDownloadPerCategoryID(
586 download_item.GetId())), 616 download_item.GetId())),
587 download_item.GetOriginalUrl()); 617 download_item.GetOriginalUrl());
588 suggestion.set_title( 618 suggestion.set_title(
589 download_item.GetTargetFilePath().BaseName().LossyDisplayName()); 619 download_item.GetTargetFilePath().BaseName().LossyDisplayName());
590 suggestion.set_publish_date(GetAssetDownloadPublishedTime(download_item)); 620 suggestion.set_publish_date(GetAssetDownloadPublishedTime(download_item));
591 suggestion.set_publisher_name( 621 suggestion.set_publisher_name(
592 base::UTF8ToUTF16(download_item.GetURL().host())); 622 base::UTF8ToUTF16(download_item.GetURL().host()));
593 auto extra = base::MakeUnique<ntp_snippets::DownloadSuggestionExtra>(); 623 auto extra = base::MakeUnique<ntp_snippets::DownloadSuggestionExtra>();
594 extra->target_file_path = download_item.GetTargetFilePath(); 624 extra->target_file_path = download_item.GetTargetFilePath();
595 extra->mime_type = download_item.GetMimeType(); 625 extra->mime_type = download_item.GetMimeType();
596 extra->is_download_asset = true; 626 extra->is_download_asset = true;
597 suggestion.set_download_suggestion_extra(std::move(extra)); 627 suggestion.set_download_suggestion_extra(std::move(extra));
598 return suggestion; 628 return suggestion;
599 } 629 }
600 630
631 bool DownloadSuggestionsProvider::IsDownloadOutdated(
632 const base::Time& published_time) {
633 // TODO(vitaliii): Also consider last access time here once it is collected
634 // for asset downloads.
635 return published_time <
636 clock_->Now() - base::TimeDelta::FromHours(GetMaxDownloadAgeHours());
637 }
638
601 bool DownloadSuggestionsProvider::CacheAssetDownloadIfNeeded( 639 bool DownloadSuggestionsProvider::CacheAssetDownloadIfNeeded(
602 const content::DownloadItem* item) { 640 const content::DownloadItem* item) {
603 if (!IsDownloadCompleted(*item)) { 641 if (!IsAssetDownloadCompleted(*item)) {
604 return false; 642 return false;
605 } 643 }
606 644
607 if (base::ContainsValue(cached_asset_downloads_, item)) { 645 if (base::ContainsValue(cached_asset_downloads_, item)) {
608 return false; 646 return false;
609 } 647 }
610 648
611 std::set<std::string> dismissed_ids = ReadAssetDismissedIDsFromPrefs(); 649 std::set<std::string> dismissed_ids = ReadAssetDismissedIDsFromPrefs();
612 if (dismissed_ids.count(GetAssetDownloadPerCategoryID(item->GetId()))) { 650 if (dismissed_ids.count(GetAssetDownloadPerCategoryID(item->GetId()))) {
613 return false; 651 return false;
614 } 652 }
615 653
616 DCHECK_LE(static_cast<int>(cached_asset_downloads_.size()), 654 DCHECK_LE(static_cast<int>(cached_asset_downloads_.size()),
617 GetMaxSuggestionsCount()); 655 GetMaxSuggestionsCount());
618 if (static_cast<int>(cached_asset_downloads_.size()) == 656 if (static_cast<int>(cached_asset_downloads_.size()) ==
619 GetMaxSuggestionsCount()) { 657 GetMaxSuggestionsCount()) {
620 auto oldest = std::max_element( 658 auto oldest = std::max_element(cached_asset_downloads_.begin(),
621 cached_asset_downloads_.begin(), cached_asset_downloads_.end(), 659 cached_asset_downloads_.end(),
622 &CompareDownloadsMostRecentlyDownloadedFirst); 660 &CompareDownloadsMostRecentlyPublishedFirst);
623 if (GetAssetDownloadPublishedTime(*item) <= 661 if (GetAssetDownloadPublishedTime(*item) <=
624 GetAssetDownloadPublishedTime(**oldest)) { 662 GetAssetDownloadPublishedTime(**oldest)) {
625 return false; 663 return false;
626 } 664 }
627 665
628 *oldest = item; 666 *oldest = item;
629 } else { 667 } else {
630 cached_asset_downloads_.push_back(item); 668 cached_asset_downloads_.push_back(item);
631 } 669 }
632 670
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
699 DCHECK(!offline_page_model_ || offline_page_model_->is_loaded()); 737 DCHECK(!offline_page_model_ || offline_page_model_->is_loaded());
700 738
701 std::set<std::string> old_dismissed_ids = 739 std::set<std::string> old_dismissed_ids =
702 ReadOfflinePageDismissedIDsFromPrefs(); 740 ReadOfflinePageDismissedIDsFromPrefs();
703 std::set<std::string> retained_dismissed_ids; 741 std::set<std::string> retained_dismissed_ids;
704 std::vector<const OfflinePageItem*> items; 742 std::vector<const OfflinePageItem*> items;
705 // Filtering out dismissed items and pruning dismissed IDs. 743 // Filtering out dismissed items and pruning dismissed IDs.
706 for (const OfflinePageItem& item : all_download_offline_pages) { 744 for (const OfflinePageItem& item : all_download_offline_pages) {
707 std::string id_within_category = 745 std::string id_within_category =
708 GetOfflinePagePerCategoryID(item.offline_id); 746 GetOfflinePagePerCategoryID(item.offline_id);
709 if (!old_dismissed_ids.count(id_within_category)) { 747 if (old_dismissed_ids.count(id_within_category)) {
710 items.push_back(&item); 748 retained_dismissed_ids.insert(id_within_category);
711 } else { 749 } else {
712 retained_dismissed_ids.insert(id_within_category); 750 if (!IsDownloadOutdated(GetOfflinePagePublishedTime(item))) {
751 items.push_back(&item);
752 }
713 } 753 }
714 } 754 }
715 755
716 const int max_suggestions_count = GetMaxSuggestionsCount(); 756 const int max_suggestions_count = GetMaxSuggestionsCount();
717 if (static_cast<int>(items.size()) > max_suggestions_count) { 757 if (static_cast<int>(items.size()) > max_suggestions_count) {
718 // Partially sorts |items| such that: 758 // Partially sorts |items| such that:
719 // 1) The element at the index |max_suggestions_count| is changed to the 759 // 1) The element at the index |max_suggestions_count| is changed to the
720 // element which would occur on this position if |items| was sorted; 760 // element which would occur on this position if |items| was sorted;
721 // 2) All of the elements before index |max_suggestions_count| are less than 761 // 2) All of the elements before index |max_suggestions_count| are less than
722 // or equal to the elements after it. 762 // or equal to the elements after it.
723 std::nth_element( 763 std::nth_element(
724 items.begin(), items.begin() + max_suggestions_count, items.end(), 764 items.begin(), items.begin() + max_suggestions_count, items.end(),
725 [](const OfflinePageItem* left, const OfflinePageItem* right) { 765 [](const OfflinePageItem* left, const OfflinePageItem* right) {
726 return CompareOfflinePagesMostRecentlyCreatedFirst(*left, *right); 766 return CompareOfflinePagesMostRecentlyPublishedFirst(*left, *right);
727 }); 767 });
728 items.resize(max_suggestions_count); 768 items.resize(max_suggestions_count);
729 } 769 }
730 770
731 cached_offline_page_downloads_.clear(); 771 cached_offline_page_downloads_.clear();
732 for (const OfflinePageItem* item : items) { 772 for (const OfflinePageItem* item : items) {
733 cached_offline_page_downloads_.push_back(*item); 773 cached_offline_page_downloads_.push_back(*item);
734 } 774 }
735 775
736 if (old_dismissed_ids.size() != retained_dismissed_ids.size()) { 776 if (old_dismissed_ids.size() != retained_dismissed_ids.size()) {
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
811 void DownloadSuggestionsProvider::UnregisterDownloadItemObservers() { 851 void DownloadSuggestionsProvider::UnregisterDownloadItemObservers() {
812 DCHECK_NE(download_manager_, nullptr); 852 DCHECK_NE(download_manager_, nullptr);
813 853
814 std::vector<DownloadItem*> all_downloads; 854 std::vector<DownloadItem*> all_downloads;
815 download_manager_->GetAllDownloads(&all_downloads); 855 download_manager_->GetAllDownloads(&all_downloads);
816 856
817 for (DownloadItem* item : all_downloads) { 857 for (DownloadItem* item : all_downloads) {
818 item->RemoveObserver(this); 858 item->RemoveObserver(this);
819 } 859 }
820 } 860 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698