Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 kDefaultMaxDownloadAgeDays = 6 * 7; // 6 weeks | |
| 47 const char kAssetDownloadsPrefix = 'D'; | 49 const char kAssetDownloadsPrefix = 'D'; |
| 48 const char kOfflinePageDownloadsPrefix = 'O'; | 50 const char kOfflinePageDownloadsPrefix = 'O'; |
| 49 | 51 |
| 50 const char* kMaxSuggestionsCountParamName = "downloads_max_count"; | 52 const char* kMaxSuggestionsCountParamName = "downloads_max_count"; |
| 53 const char* kMaxDownloadAgeDaysParamName = "downloads_max_age_days"; | |
| 51 | 54 |
| 52 bool CompareOfflinePagesMostRecentlyCreatedFirst(const OfflinePageItem& left, | 55 base::Time GetOfflinePagePublishedTime(const OfflinePageItem& item) { |
| 53 const OfflinePageItem& right) { | 56 return item.creation_time; |
| 54 return left.creation_time > right.creation_time; | 57 } |
| 58 | |
| 59 bool CompareOfflinePagesMostRecentlyPublishedFirst( | |
| 60 const OfflinePageItem& left, | |
| 61 const OfflinePageItem& right) { | |
| 62 return GetOfflinePagePublishedTime(left) > GetOfflinePagePublishedTime(right); | |
| 55 } | 63 } |
| 56 | 64 |
| 57 int GetMaxSuggestionsCount() { | 65 int GetMaxSuggestionsCount() { |
| 58 bool assets_enabled = | 66 bool assets_enabled = |
| 59 base::FeatureList::IsEnabled(features::kAssetDownloadSuggestionsFeature); | 67 base::FeatureList::IsEnabled(features::kAssetDownloadSuggestionsFeature); |
| 60 return variations::GetVariationParamByFeatureAsInt( | 68 return variations::GetVariationParamByFeatureAsInt( |
| 61 assets_enabled ? features::kAssetDownloadSuggestionsFeature | 69 assets_enabled ? features::kAssetDownloadSuggestionsFeature |
| 62 : features::kOfflinePageDownloadSuggestionsFeature, | 70 : features::kOfflinePageDownloadSuggestionsFeature, |
| 63 kMaxSuggestionsCountParamName, kDefaultMaxSuggestionsCount); | 71 kMaxSuggestionsCountParamName, kDefaultMaxSuggestionsCount); |
| 64 } | 72 } |
| 65 | 73 |
| 74 int GetMaxDownloadAgeDays() { | |
| 75 bool assets_enabled = | |
| 76 base::FeatureList::IsEnabled(features::kAssetDownloadSuggestionsFeature); | |
| 77 return variations::GetVariationParamByFeatureAsInt( | |
| 78 assets_enabled ? features::kAssetDownloadSuggestionsFeature | |
|
tschumann
2017/02/02 14:30:33
+Jan, can you double-check this is sane?
It's the
jkrcal
2017/02/02 16:06:16
After offline discussion, this is sane, please add
vitaliii
2017/02/07 10:26:05
Done.
I added comments.
|GetVariationParamByFea
| |
| 79 : features::kOfflinePageDownloadSuggestionsFeature, | |
| 80 kMaxDownloadAgeDaysParamName, kDefaultMaxDownloadAgeDays); | |
| 81 } | |
| 82 | |
| 66 std::string GetOfflinePagePerCategoryID(int64_t raw_offline_page_id) { | 83 std::string GetOfflinePagePerCategoryID(int64_t raw_offline_page_id) { |
| 67 // Raw ID is prefixed in order to avoid conflicts with asset downloads. | 84 // Raw ID is prefixed in order to avoid conflicts with asset downloads. |
| 68 return std::string(1, kOfflinePageDownloadsPrefix) + | 85 return std::string(1, kOfflinePageDownloadsPrefix) + |
| 69 base::IntToString(raw_offline_page_id); | 86 base::IntToString(raw_offline_page_id); |
| 70 } | 87 } |
| 71 | 88 |
| 72 std::string GetAssetDownloadPerCategoryID(uint32_t raw_download_id) { | 89 std::string GetAssetDownloadPerCategoryID(uint32_t raw_download_id) { |
| 73 // Raw ID is prefixed in order to avoid conflicts with offline page downloads. | 90 // Raw ID is prefixed in order to avoid conflicts with offline page downloads. |
| 74 return std::string(1, kAssetDownloadsPrefix) + | 91 return std::string(1, kAssetDownloadsPrefix) + |
| 75 base::UintToString(raw_download_id); | 92 base::UintToString(raw_download_id); |
| 76 } | 93 } |
| 77 | 94 |
| 78 // Determines whether |suggestion_id| corresponds to offline page suggestion or | 95 // Determines whether |suggestion_id| corresponds to offline page suggestion or |
| 79 // asset download based on |id_within_category| prefix. | 96 // asset download based on |id_within_category| prefix. |
| 80 bool CorrespondsToOfflinePage(const ContentSuggestion::ID& suggestion_id) { | 97 bool CorrespondsToOfflinePage(const ContentSuggestion::ID& suggestion_id) { |
| 81 const std::string& id_within_category = suggestion_id.id_within_category(); | 98 const std::string& id_within_category = suggestion_id.id_within_category(); |
| 82 if (!id_within_category.empty()) { | 99 if (!id_within_category.empty()) { |
| 83 if (id_within_category[0] == kOfflinePageDownloadsPrefix) { | 100 if (id_within_category[0] == kOfflinePageDownloadsPrefix) { |
| 84 return true; | 101 return true; |
| 85 } | 102 } |
| 86 if (id_within_category[0] == kAssetDownloadsPrefix) { | 103 if (id_within_category[0] == kAssetDownloadsPrefix) { |
| 87 return false; | 104 return false; |
| 88 } | 105 } |
| 89 } | 106 } |
| 90 NOTREACHED() << "Unknown id_within_category " << id_within_category; | 107 NOTREACHED() << "Unknown id_within_category " << id_within_category; |
| 91 return false; | 108 return false; |
| 92 } | 109 } |
| 93 | 110 |
| 94 bool IsDownloadCompleted(const DownloadItem& item) { | 111 bool IsAssetDownloadCompleted(const DownloadItem& item) { |
| 95 return item.GetState() == DownloadItem::DownloadState::COMPLETE && | 112 return item.GetState() == DownloadItem::DownloadState::COMPLETE && |
| 96 !item.GetFileExternallyRemoved(); | 113 !item.GetFileExternallyRemoved(); |
| 97 } | 114 } |
| 98 | 115 |
| 99 base::Time GetAssetDownloadPublishedTime(const DownloadItem& item) { | 116 base::Time GetAssetDownloadPublishedTime(const DownloadItem& item) { |
| 100 return item.GetStartTime(); | 117 return item.GetStartTime(); |
| 101 } | 118 } |
| 102 | 119 |
| 103 bool CompareDownloadsMostRecentlyDownloadedFirst(const DownloadItem* left, | 120 bool CompareDownloadsMostRecentlyPublishedFirst(const DownloadItem* left, |
| 104 const DownloadItem* right) { | 121 const DownloadItem* right) { |
| 105 return GetAssetDownloadPublishedTime(*left) > | 122 return GetAssetDownloadPublishedTime(*left) > |
| 106 GetAssetDownloadPublishedTime(*right); | 123 GetAssetDownloadPublishedTime(*right); |
| 107 } | 124 } |
| 108 | 125 |
| 109 bool IsClientIdForOfflinePageDownload( | 126 bool IsClientIdForOfflinePageDownload( |
| 110 offline_pages::ClientPolicyController* policy_controller, | 127 offline_pages::ClientPolicyController* policy_controller, |
| 111 const offline_pages::ClientId& client_id) { | 128 const offline_pages::ClientId& client_id) { |
| 112 return policy_controller->IsSupportedByDownload(client_id.name_space); | 129 return policy_controller->IsSupportedByDownload(client_id.name_space); |
| 113 } | 130 } |
| 114 | 131 |
| 115 std::unique_ptr<OfflinePageModelQuery> BuildOfflinePageDownloadsQuery( | 132 std::unique_ptr<OfflinePageModelQuery> BuildOfflinePageDownloadsQuery( |
| 116 offline_pages::OfflinePageModel* model) { | 133 offline_pages::OfflinePageModel* model) { |
| 117 OfflinePageModelQueryBuilder builder; | 134 OfflinePageModelQueryBuilder builder; |
| 118 builder.RequireSupportedByDownload( | 135 builder.RequireSupportedByDownload( |
| 119 OfflinePageModelQuery::Requirement::INCLUDE_MATCHING); | 136 OfflinePageModelQuery::Requirement::INCLUDE_MATCHING); |
| 120 return builder.Build(model->GetPolicyController()); | 137 return builder.Build(model->GetPolicyController()); |
| 121 } | 138 } |
| 122 | 139 |
| 123 } // namespace | 140 } // namespace |
| 124 | 141 |
| 125 DownloadSuggestionsProvider::DownloadSuggestionsProvider( | 142 DownloadSuggestionsProvider::DownloadSuggestionsProvider( |
| 126 ContentSuggestionsProvider::Observer* observer, | 143 ContentSuggestionsProvider::Observer* observer, |
| 127 offline_pages::OfflinePageModel* offline_page_model, | 144 offline_pages::OfflinePageModel* offline_page_model, |
| 128 content::DownloadManager* download_manager, | 145 content::DownloadManager* download_manager, |
| 129 DownloadHistory* download_history, | 146 DownloadHistory* download_history, |
| 130 PrefService* pref_service) | 147 PrefService* pref_service, |
| 148 std::unique_ptr<base::Clock> clock) | |
| 131 : ContentSuggestionsProvider(observer), | 149 : ContentSuggestionsProvider(observer), |
| 132 category_status_(CategoryStatus::AVAILABLE_LOADING), | 150 category_status_(CategoryStatus::AVAILABLE_LOADING), |
| 133 provided_category_(Category::FromKnownCategory( | 151 provided_category_(Category::FromKnownCategory( |
| 134 ntp_snippets::KnownCategories::DOWNLOADS)), | 152 ntp_snippets::KnownCategories::DOWNLOADS)), |
| 135 offline_page_model_(offline_page_model), | 153 offline_page_model_(offline_page_model), |
| 136 download_manager_(download_manager), | 154 download_manager_(download_manager), |
| 137 download_history_(download_history), | 155 download_history_(download_history), |
| 138 pref_service_(pref_service), | 156 pref_service_(pref_service), |
| 157 clock_(std::move(clock)), | |
| 139 is_asset_downloads_initialization_complete_(false), | 158 is_asset_downloads_initialization_complete_(false), |
| 140 weak_ptr_factory_(this) { | 159 weak_ptr_factory_(this) { |
| 141 observer->OnCategoryStatusChanged(this, provided_category_, category_status_); | 160 observer->OnCategoryStatusChanged(this, provided_category_, category_status_); |
| 142 | 161 |
| 143 DCHECK(offline_page_model_ || download_manager_); | 162 DCHECK(offline_page_model_ || download_manager_); |
| 144 if (offline_page_model_) { | 163 if (offline_page_model_) { |
| 145 offline_page_model_->AddObserver(this); | 164 offline_page_model_->AddObserver(this); |
| 146 } | 165 } |
| 147 | 166 |
| 148 if (download_manager_) { | 167 if (download_manager_) { |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 338 0U); | 357 0U); |
| 339 | 358 |
| 340 int max_suggestions_count = GetMaxSuggestionsCount(); | 359 int max_suggestions_count = GetMaxSuggestionsCount(); |
| 341 if (static_cast<int>(cached_offline_page_downloads_.size()) < | 360 if (static_cast<int>(cached_offline_page_downloads_.size()) < |
| 342 max_suggestions_count) { | 361 max_suggestions_count) { |
| 343 cached_offline_page_downloads_.push_back(added_page); | 362 cached_offline_page_downloads_.push_back(added_page); |
| 344 } else if (max_suggestions_count > 0) { | 363 } else if (max_suggestions_count > 0) { |
| 345 auto oldest_page_iterator = | 364 auto oldest_page_iterator = |
| 346 std::max_element(cached_offline_page_downloads_.begin(), | 365 std::max_element(cached_offline_page_downloads_.begin(), |
| 347 cached_offline_page_downloads_.end(), | 366 cached_offline_page_downloads_.end(), |
| 348 &CompareOfflinePagesMostRecentlyCreatedFirst); | 367 &CompareOfflinePagesMostRecentlyPublishedFirst); |
| 349 *oldest_page_iterator = added_page; | 368 *oldest_page_iterator = added_page; |
| 350 } | 369 } |
| 351 | 370 |
| 352 SubmitContentSuggestions(); | 371 SubmitContentSuggestions(); |
| 353 } | 372 } |
| 354 | 373 |
| 355 void DownloadSuggestionsProvider::OfflinePageDeleted( | 374 void DownloadSuggestionsProvider::OfflinePageDeleted( |
| 356 int64_t offline_id, | 375 int64_t offline_id, |
| 357 const offline_pages::ClientId& client_id) { | 376 const offline_pages::ClientId& client_id) { |
| 358 DCHECK(offline_page_model_); | 377 DCHECK(offline_page_model_); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 411 // we may need to retrieve all downloads, but |OnDownloadRemoved| is called | 430 // we may need to retrieve all downloads, but |OnDownloadRemoved| is called |
| 412 // before the download is removed from the list. | 431 // before the download is removed from the list. |
| 413 } | 432 } |
| 414 | 433 |
| 415 void DownloadSuggestionsProvider::OnDownloadDestroyed( | 434 void DownloadSuggestionsProvider::OnDownloadDestroyed( |
| 416 content::DownloadItem* item) { | 435 content::DownloadItem* item) { |
| 417 DCHECK(is_asset_downloads_initialization_complete_); | 436 DCHECK(is_asset_downloads_initialization_complete_); |
| 418 | 437 |
| 419 item->RemoveObserver(this); | 438 item->RemoveObserver(this); |
| 420 | 439 |
| 421 if (!IsDownloadCompleted(*item)) { | 440 if (!IsAssetDownloadCompleted(*item)) { |
| 422 return; | 441 return; |
| 423 } | 442 } |
| 424 // TODO(vitaliii): Implement a better way to clean up dismissed IDs (in case | 443 // TODO(vitaliii): Implement a better way to clean up dismissed IDs (in case |
| 425 // some calls are missed). | 444 // some calls are missed). |
| 426 InvalidateSuggestion(GetAssetDownloadPerCategoryID(item->GetId())); | 445 InvalidateSuggestion(GetAssetDownloadPerCategoryID(item->GetId())); |
| 427 } | 446 } |
| 428 | 447 |
| 429 void DownloadSuggestionsProvider::OnHistoryQueryComplete() { | 448 void DownloadSuggestionsProvider::OnHistoryQueryComplete() { |
| 430 is_asset_downloads_initialization_complete_ = true; | 449 is_asset_downloads_initialization_complete_ = true; |
| 431 if (download_manager_) { | 450 if (download_manager_) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 485 std::vector<DownloadItem*> all_downloads; | 504 std::vector<DownloadItem*> all_downloads; |
| 486 download_manager_->GetAllDownloads(&all_downloads); | 505 download_manager_->GetAllDownloads(&all_downloads); |
| 487 std::set<std::string> old_dismissed_ids = ReadAssetDismissedIDsFromPrefs(); | 506 std::set<std::string> old_dismissed_ids = ReadAssetDismissedIDsFromPrefs(); |
| 488 std::set<std::string> retained_dismissed_ids; | 507 std::set<std::string> retained_dismissed_ids; |
| 489 cached_asset_downloads_.clear(); | 508 cached_asset_downloads_.clear(); |
| 490 for (DownloadItem* item : all_downloads) { | 509 for (DownloadItem* item : all_downloads) { |
| 491 std::string within_category_id = | 510 std::string within_category_id = |
| 492 GetAssetDownloadPerCategoryID(item->GetId()); | 511 GetAssetDownloadPerCategoryID(item->GetId()); |
| 493 if (old_dismissed_ids.count(within_category_id)) { | 512 if (old_dismissed_ids.count(within_category_id)) { |
| 494 retained_dismissed_ids.insert(within_category_id); | 513 retained_dismissed_ids.insert(within_category_id); |
| 495 } else if (IsDownloadCompleted(*item)) { | 514 } else if (IsAssetDownloadCompleted(*item) && |
| 515 !IsDownloadOld(GetAssetDownloadPublishedTime(*item))) { | |
| 496 cached_asset_downloads_.push_back(item); | 516 cached_asset_downloads_.push_back(item); |
| 497 // We may already observe this item and, therefore, we remove the | 517 // We may already observe this item and, therefore, we remove the |
| 498 // observer first. | 518 // observer first. |
| 499 item->RemoveObserver(this); | 519 item->RemoveObserver(this); |
| 500 item->AddObserver(this); | 520 item->AddObserver(this); |
| 501 } | 521 } |
| 502 } | 522 } |
| 503 | 523 |
| 504 if (old_dismissed_ids.size() != retained_dismissed_ids.size()) { | 524 if (old_dismissed_ids.size() != retained_dismissed_ids.size()) { |
| 505 StoreAssetDismissedIDsToPrefs(retained_dismissed_ids); | 525 StoreAssetDismissedIDsToPrefs(retained_dismissed_ids); |
| 506 } | 526 } |
| 507 | 527 |
| 508 const int max_suggestions_count = GetMaxSuggestionsCount(); | 528 const int max_suggestions_count = GetMaxSuggestionsCount(); |
| 509 if (static_cast<int>(cached_asset_downloads_.size()) > | 529 if (static_cast<int>(cached_asset_downloads_.size()) > |
| 510 max_suggestions_count) { | 530 max_suggestions_count) { |
| 511 // Partially sorts |downloads| such that: | 531 // Partially sorts |downloads| such that: |
| 512 // 1) The element at the index |max_suggestions_count| is changed to the | 532 // 1) The element at the index |max_suggestions_count| is changed to the |
| 513 // element which would occur on this position if |downloads| was sorted; | 533 // element which would occur on this position if |downloads| was sorted; |
| 514 // 2) All of the elements before index |max_suggestions_count| are less than | 534 // 2) All of the elements before index |max_suggestions_count| are less than |
| 515 // or equal to the elements after it. | 535 // or equal to the elements after it. |
| 516 std::nth_element(cached_asset_downloads_.begin(), | 536 std::nth_element(cached_asset_downloads_.begin(), |
| 517 cached_asset_downloads_.begin() + max_suggestions_count, | 537 cached_asset_downloads_.begin() + max_suggestions_count, |
| 518 cached_asset_downloads_.end(), | 538 cached_asset_downloads_.end(), |
| 519 &CompareDownloadsMostRecentlyDownloadedFirst); | 539 &CompareDownloadsMostRecentlyPublishedFirst); |
| 520 cached_asset_downloads_.resize(max_suggestions_count); | 540 cached_asset_downloads_.resize(max_suggestions_count); |
| 521 } | 541 } |
| 522 } | 542 } |
| 523 | 543 |
| 524 void DownloadSuggestionsProvider:: | 544 void DownloadSuggestionsProvider:: |
| 525 AsynchronouslyFetchAllDownloadsAndSubmitSuggestions() { | 545 AsynchronouslyFetchAllDownloadsAndSubmitSuggestions() { |
| 526 FetchAssetsDownloads(); | 546 FetchAssetsDownloads(); |
| 527 AsynchronouslyFetchOfflinePagesDownloads(/*notify=*/true); | 547 AsynchronouslyFetchOfflinePagesDownloads(/*notify=*/true); |
| 528 } | 548 } |
| 529 | 549 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 561 offline_page.offline_id)), | 581 offline_page.offline_id)), |
| 562 offline_page.url); | 582 offline_page.url); |
| 563 | 583 |
| 564 if (offline_page.title.empty()) { | 584 if (offline_page.title.empty()) { |
| 565 // TODO(vitaliii): Remove this fallback once the OfflinePageModel provides | 585 // TODO(vitaliii): Remove this fallback once the OfflinePageModel provides |
| 566 // titles for all (relevant) OfflinePageItems. | 586 // titles for all (relevant) OfflinePageItems. |
| 567 suggestion.set_title(base::UTF8ToUTF16(offline_page.url.spec())); | 587 suggestion.set_title(base::UTF8ToUTF16(offline_page.url.spec())); |
| 568 } else { | 588 } else { |
| 569 suggestion.set_title(offline_page.title); | 589 suggestion.set_title(offline_page.title); |
| 570 } | 590 } |
| 571 suggestion.set_publish_date(offline_page.creation_time); | 591 suggestion.set_publish_date(GetOfflinePagePublishedTime(offline_page)); |
| 572 suggestion.set_publisher_name(base::UTF8ToUTF16(offline_page.url.host())); | 592 suggestion.set_publisher_name(base::UTF8ToUTF16(offline_page.url.host())); |
| 573 auto extra = base::MakeUnique<ntp_snippets::DownloadSuggestionExtra>(); | 593 auto extra = base::MakeUnique<ntp_snippets::DownloadSuggestionExtra>(); |
| 574 extra->is_download_asset = false; | 594 extra->is_download_asset = false; |
| 575 extra->offline_page_id = offline_page.offline_id; | 595 extra->offline_page_id = offline_page.offline_id; |
| 576 suggestion.set_download_suggestion_extra(std::move(extra)); | 596 suggestion.set_download_suggestion_extra(std::move(extra)); |
| 577 return suggestion; | 597 return suggestion; |
| 578 } | 598 } |
| 579 | 599 |
| 580 ContentSuggestion DownloadSuggestionsProvider::ConvertDownloadItem( | 600 ContentSuggestion DownloadSuggestionsProvider::ConvertDownloadItem( |
| 581 const DownloadItem& download_item) const { | 601 const DownloadItem& download_item) const { |
| 582 ContentSuggestion suggestion( | 602 ContentSuggestion suggestion( |
| 583 ContentSuggestion::ID(provided_category_, GetAssetDownloadPerCategoryID( | 603 ContentSuggestion::ID(provided_category_, GetAssetDownloadPerCategoryID( |
| 584 download_item.GetId())), | 604 download_item.GetId())), |
| 585 download_item.GetOriginalUrl()); | 605 download_item.GetOriginalUrl()); |
| 586 suggestion.set_title( | 606 suggestion.set_title( |
| 587 download_item.GetTargetFilePath().BaseName().LossyDisplayName()); | 607 download_item.GetTargetFilePath().BaseName().LossyDisplayName()); |
| 588 suggestion.set_publish_date(GetAssetDownloadPublishedTime(download_item)); | 608 suggestion.set_publish_date(GetAssetDownloadPublishedTime(download_item)); |
| 589 suggestion.set_publisher_name( | 609 suggestion.set_publisher_name( |
| 590 base::UTF8ToUTF16(download_item.GetURL().host())); | 610 base::UTF8ToUTF16(download_item.GetURL().host())); |
| 591 auto extra = base::MakeUnique<ntp_snippets::DownloadSuggestionExtra>(); | 611 auto extra = base::MakeUnique<ntp_snippets::DownloadSuggestionExtra>(); |
| 592 extra->target_file_path = download_item.GetTargetFilePath(); | 612 extra->target_file_path = download_item.GetTargetFilePath(); |
| 593 extra->mime_type = download_item.GetMimeType(); | 613 extra->mime_type = download_item.GetMimeType(); |
| 594 extra->is_download_asset = true; | 614 extra->is_download_asset = true; |
| 595 suggestion.set_download_suggestion_extra(std::move(extra)); | 615 suggestion.set_download_suggestion_extra(std::move(extra)); |
| 596 return suggestion; | 616 return suggestion; |
| 597 } | 617 } |
| 598 | 618 |
| 619 bool DownloadSuggestionsProvider::IsDownloadOld( | |
| 620 const base::Time& published_time) { | |
| 621 // TODO(vitaliii): Also consider last access time here once it is collected | |
| 622 // for asset downloads. | |
| 623 return published_time < | |
| 624 clock_->Now() - base::TimeDelta::FromDays(GetMaxDownloadAgeDays()); | |
| 625 } | |
| 626 | |
| 599 bool DownloadSuggestionsProvider::CacheAssetDownloadIfNeeded( | 627 bool DownloadSuggestionsProvider::CacheAssetDownloadIfNeeded( |
| 600 const content::DownloadItem* item) { | 628 const content::DownloadItem* item) { |
| 601 if (!IsDownloadCompleted(*item)) { | 629 if (!IsAssetDownloadCompleted(*item)) { |
| 602 return false; | 630 return false; |
| 603 } | 631 } |
| 604 | 632 |
| 605 if (base::ContainsValue(cached_asset_downloads_, item)) { | 633 if (base::ContainsValue(cached_asset_downloads_, item)) { |
| 606 return false; | 634 return false; |
| 607 } | 635 } |
| 608 | 636 |
| 609 std::set<std::string> dismissed_ids = ReadAssetDismissedIDsFromPrefs(); | 637 std::set<std::string> dismissed_ids = ReadAssetDismissedIDsFromPrefs(); |
| 610 if (dismissed_ids.count(GetAssetDownloadPerCategoryID(item->GetId()))) { | 638 if (dismissed_ids.count(GetAssetDownloadPerCategoryID(item->GetId()))) { |
| 611 return false; | 639 return false; |
| 612 } | 640 } |
| 613 | 641 |
| 614 DCHECK_LE(static_cast<int>(cached_asset_downloads_.size()), | 642 DCHECK_LE(static_cast<int>(cached_asset_downloads_.size()), |
| 615 GetMaxSuggestionsCount()); | 643 GetMaxSuggestionsCount()); |
| 616 if (static_cast<int>(cached_asset_downloads_.size()) == | 644 if (static_cast<int>(cached_asset_downloads_.size()) == |
| 617 GetMaxSuggestionsCount()) { | 645 GetMaxSuggestionsCount()) { |
| 618 auto oldest = std::max_element( | 646 auto oldest = std::max_element(cached_asset_downloads_.begin(), |
| 619 cached_asset_downloads_.begin(), cached_asset_downloads_.end(), | 647 cached_asset_downloads_.end(), |
| 620 &CompareDownloadsMostRecentlyDownloadedFirst); | 648 &CompareDownloadsMostRecentlyPublishedFirst); |
| 621 if (GetAssetDownloadPublishedTime(*item) <= | 649 if (GetAssetDownloadPublishedTime(*item) <= |
| 622 GetAssetDownloadPublishedTime(**oldest)) { | 650 GetAssetDownloadPublishedTime(**oldest)) { |
| 623 return false; | 651 return false; |
| 624 } | 652 } |
| 625 | 653 |
| 626 *oldest = item; | 654 *oldest = item; |
| 627 } else { | 655 } else { |
| 628 cached_asset_downloads_.push_back(item); | 656 cached_asset_downloads_.push_back(item); |
| 629 } | 657 } |
| 630 | 658 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 697 DCHECK(!offline_page_model_ || offline_page_model_->is_loaded()); | 725 DCHECK(!offline_page_model_ || offline_page_model_->is_loaded()); |
| 698 | 726 |
| 699 std::set<std::string> old_dismissed_ids = | 727 std::set<std::string> old_dismissed_ids = |
| 700 ReadOfflinePageDismissedIDsFromPrefs(); | 728 ReadOfflinePageDismissedIDsFromPrefs(); |
| 701 std::set<std::string> retained_dismissed_ids; | 729 std::set<std::string> retained_dismissed_ids; |
| 702 std::vector<const OfflinePageItem*> items; | 730 std::vector<const OfflinePageItem*> items; |
| 703 // Filtering out dismissed items and pruning dismissed IDs. | 731 // Filtering out dismissed items and pruning dismissed IDs. |
| 704 for (const OfflinePageItem& item : all_download_offline_pages) { | 732 for (const OfflinePageItem& item : all_download_offline_pages) { |
| 705 std::string id_within_category = | 733 std::string id_within_category = |
| 706 GetOfflinePagePerCategoryID(item.offline_id); | 734 GetOfflinePagePerCategoryID(item.offline_id); |
| 707 if (!old_dismissed_ids.count(id_within_category)) { | 735 if (!old_dismissed_ids.count(id_within_category)) { |
|
tschumann
2017/02/02 14:30:33
nit: It's now harder to get the context of the the
vitaliii
2017/02/07 10:26:05
Done. I've inversed the outer |if|.
| |
| 708 items.push_back(&item); | 736 if (!IsDownloadOld(GetOfflinePagePublishedTime(item))) { |
|
vitaliii
2017/02/02 14:06:55
tschumann@, do we want to use last access time for
tschumann
2017/02/02 14:30:33
i'm fine doing this in one CL.
vitaliii
2017/02/07 10:26:05
Acknowledged.
| |
| 737 items.push_back(&item); | |
| 738 } | |
| 709 } else { | 739 } else { |
| 710 retained_dismissed_ids.insert(id_within_category); | 740 retained_dismissed_ids.insert(id_within_category); |
| 711 } | 741 } |
| 712 } | 742 } |
| 713 | 743 |
| 714 const int max_suggestions_count = GetMaxSuggestionsCount(); | 744 const int max_suggestions_count = GetMaxSuggestionsCount(); |
| 715 if (static_cast<int>(items.size()) > max_suggestions_count) { | 745 if (static_cast<int>(items.size()) > max_suggestions_count) { |
| 716 // Partially sorts |items| such that: | 746 // Partially sorts |items| such that: |
| 717 // 1) The element at the index |max_suggestions_count| is changed to the | 747 // 1) The element at the index |max_suggestions_count| is changed to the |
| 718 // element which would occur on this position if |items| was sorted; | 748 // element which would occur on this position if |items| was sorted; |
| 719 // 2) All of the elements before index |max_suggestions_count| are less than | 749 // 2) All of the elements before index |max_suggestions_count| are less than |
| 720 // or equal to the elements after it. | 750 // or equal to the elements after it. |
| 721 std::nth_element( | 751 std::nth_element( |
| 722 items.begin(), items.begin() + max_suggestions_count, items.end(), | 752 items.begin(), items.begin() + max_suggestions_count, items.end(), |
| 723 [](const OfflinePageItem* left, const OfflinePageItem* right) { | 753 [](const OfflinePageItem* left, const OfflinePageItem* right) { |
| 724 return CompareOfflinePagesMostRecentlyCreatedFirst(*left, *right); | 754 return CompareOfflinePagesMostRecentlyPublishedFirst(*left, *right); |
| 725 }); | 755 }); |
| 726 items.resize(max_suggestions_count); | 756 items.resize(max_suggestions_count); |
| 727 } | 757 } |
| 728 | 758 |
| 729 cached_offline_page_downloads_.clear(); | 759 cached_offline_page_downloads_.clear(); |
| 730 for (const OfflinePageItem* item : items) { | 760 for (const OfflinePageItem* item : items) { |
| 731 cached_offline_page_downloads_.push_back(*item); | 761 cached_offline_page_downloads_.push_back(*item); |
| 732 } | 762 } |
| 733 | 763 |
| 734 if (old_dismissed_ids.size() != retained_dismissed_ids.size()) { | 764 if (old_dismissed_ids.size() != retained_dismissed_ids.size()) { |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 809 void DownloadSuggestionsProvider::UnregisterDownloadItemObservers() { | 839 void DownloadSuggestionsProvider::UnregisterDownloadItemObservers() { |
| 810 DCHECK_NE(download_manager_, nullptr); | 840 DCHECK_NE(download_manager_, nullptr); |
| 811 | 841 |
| 812 std::vector<DownloadItem*> all_downloads; | 842 std::vector<DownloadItem*> all_downloads; |
| 813 download_manager_->GetAllDownloads(&all_downloads); | 843 download_manager_->GetAllDownloads(&all_downloads); |
| 814 | 844 |
| 815 for (DownloadItem* item : all_downloads) { | 845 for (DownloadItem* item : all_downloads) { |
| 816 item->RemoveObserver(this); | 846 item->RemoveObserver(this); |
| 817 } | 847 } |
| 818 } | 848 } |
| OLD | NEW |