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

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

Issue 2629603002: [NTP::Downloads] Fetch assets once the manager is loaded. (Closed)
Patch Set: Created 3 years, 11 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/time.h" 19 #include "base/time/time.h"
20 #include "base/values.h"
21 #include "chrome/common/chrome_features.h" 20 #include "chrome/common/chrome_features.h"
22 #include "chrome/grit/generated_resources.h" 21 #include "chrome/grit/generated_resources.h"
23 #include "components/ntp_snippets/features.h" 22 #include "components/ntp_snippets/features.h"
24 #include "components/ntp_snippets/pref_names.h" 23 #include "components/ntp_snippets/pref_names.h"
25 #include "components/ntp_snippets/pref_util.h" 24 #include "components/ntp_snippets/pref_util.h"
26 #include "components/offline_pages/core/offline_page_model_query.h" 25 #include "components/offline_pages/core/offline_page_model_query.h"
27 #include "components/prefs/pref_registry_simple.h" 26 #include "components/prefs/pref_registry_simple.h"
28 #include "components/prefs/pref_service.h" 27 #include "components/prefs/pref_service.h"
29 #include "components/variations/variations_associated_data.h" 28 #include "components/variations/variations_associated_data.h"
30 #include "ui/base/l10n/l10n_util.h" 29 #include "ui/base/l10n/l10n_util.h"
31 #include "ui/gfx/image/image.h" 30 #include "ui/gfx/image/image.h"
32 31
33 using base::ContainsValue;
34 using content::DownloadItem; 32 using content::DownloadItem;
35 using content::DownloadManager; 33 using content::DownloadManager;
36 using ntp_snippets::Category; 34 using ntp_snippets::Category;
37 using ntp_snippets::CategoryInfo; 35 using ntp_snippets::CategoryInfo;
38 using ntp_snippets::CategoryStatus; 36 using ntp_snippets::CategoryStatus;
39 using ntp_snippets::ContentSuggestion; 37 using ntp_snippets::ContentSuggestion;
40 using ntp_snippets::prefs::kDismissedAssetDownloadSuggestions; 38 using ntp_snippets::prefs::kDismissedAssetDownloadSuggestions;
41 using ntp_snippets::prefs::kDismissedOfflinePageDownloadSuggestions; 39 using ntp_snippets::prefs::kDismissedOfflinePageDownloadSuggestions;
42 using offline_pages::OfflinePageItem; 40 using offline_pages::OfflinePageItem;
43 using offline_pages::OfflinePageModelQuery; 41 using offline_pages::OfflinePageModelQuery;
44 using offline_pages::OfflinePageModelQueryBuilder; 42 using offline_pages::OfflinePageModelQueryBuilder;
45 43
46 namespace { 44 namespace {
47 45
48 const int kDefaultMaxSuggestionsCount = 5; 46 const int kDefaultMaxSuggestionsCount = 5;
49 const char kAssetDownloadsPrefix = 'D'; 47 const char kAssetDownloadsPrefix = 'D';
50 const char kOfflinePageDownloadsPrefix = 'O'; 48 const char kOfflinePageDownloadsPrefix = 'O';
51 49
52 const char* kMaxSuggestionsCountParamName = "downloads_max_count"; 50 const char* kMaxSuggestionsCountParamName = "downloads_max_count";
53 51
54 // Maximal number of dismissed asset download IDs stored at any time.
55 const int kMaxDismissedIdCount = 100;
56
57 bool CompareOfflinePagesMostRecentlyCreatedFirst(const OfflinePageItem& left, 52 bool CompareOfflinePagesMostRecentlyCreatedFirst(const OfflinePageItem& left,
58 const OfflinePageItem& right) { 53 const OfflinePageItem& right) {
59 return left.creation_time > right.creation_time; 54 return left.creation_time > right.creation_time;
60 } 55 }
61 56
62 int GetMaxSuggestionsCount() { 57 int GetMaxSuggestionsCount() {
63 bool assets_enabled = 58 bool assets_enabled =
64 base::FeatureList::IsEnabled(features::kAssetDownloadSuggestionsFeature); 59 base::FeatureList::IsEnabled(features::kAssetDownloadSuggestionsFeature);
65 return variations::GetVariationParamByFeatureAsInt( 60 return variations::GetVariationParamByFeatureAsInt(
66 assets_enabled ? features::kAssetDownloadSuggestionsFeature 61 assets_enabled ? features::kAssetDownloadSuggestionsFeature
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 OfflinePageModelQuery::Requirement::INCLUDE_MATCHING); 119 OfflinePageModelQuery::Requirement::INCLUDE_MATCHING);
125 return builder.Build(model->GetPolicyController()); 120 return builder.Build(model->GetPolicyController());
126 } 121 }
127 122
128 } // namespace 123 } // namespace
129 124
130 DownloadSuggestionsProvider::DownloadSuggestionsProvider( 125 DownloadSuggestionsProvider::DownloadSuggestionsProvider(
131 ContentSuggestionsProvider::Observer* observer, 126 ContentSuggestionsProvider::Observer* observer,
132 offline_pages::OfflinePageModel* offline_page_model, 127 offline_pages::OfflinePageModel* offline_page_model,
133 content::DownloadManager* download_manager, 128 content::DownloadManager* download_manager,
129 DownloadHistory* download_history,
134 PrefService* pref_service, 130 PrefService* pref_service,
135 bool download_manager_ui_enabled) 131 bool download_manager_ui_enabled)
136 : ContentSuggestionsProvider(observer), 132 : ContentSuggestionsProvider(observer),
137 category_status_(CategoryStatus::AVAILABLE_LOADING), 133 category_status_(CategoryStatus::AVAILABLE_LOADING),
138 provided_category_(Category::FromKnownCategory( 134 provided_category_(Category::FromKnownCategory(
139 ntp_snippets::KnownCategories::DOWNLOADS)), 135 ntp_snippets::KnownCategories::DOWNLOADS)),
140 offline_page_model_(offline_page_model), 136 offline_page_model_(offline_page_model),
141 download_manager_(download_manager), 137 download_manager_(download_manager),
138 download_history_(download_history),
142 pref_service_(pref_service), 139 pref_service_(pref_service),
143 download_manager_ui_enabled_(download_manager_ui_enabled), 140 download_manager_ui_enabled_(download_manager_ui_enabled),
141 is_download_manager_loaded_(false),
144 weak_ptr_factory_(this) { 142 weak_ptr_factory_(this) {
145 observer->OnCategoryStatusChanged(this, provided_category_, category_status_); 143 observer->OnCategoryStatusChanged(this, provided_category_, category_status_);
146 144
147 DCHECK(offline_page_model_ || download_manager_); 145 DCHECK(offline_page_model_ || download_manager_);
148 if (offline_page_model_) { 146 if (offline_page_model_) {
149 offline_page_model_->AddObserver(this); 147 offline_page_model_->AddObserver(this);
150 } 148 }
151 149
152 if (download_manager_) { 150 if (download_manager_) {
153 download_manager_->AddObserver(this); 151 download_manager_->AddObserver(this);
152 // May be nullptr in tests.
153 if (download_history_) {
154 download_history_->AddObserver(this);
155 }
154 } 156 }
155 157
156 // We explicitly fetch the asset downloads in case some of |OnDownloadCreated| 158 if (!download_manager_) {
157 // happened earlier and, therefore, were missed. 159 // All downloads are fetched when the download manager is loaded, but if it
158 AsynchronouslyFetchAllDownloadsAndSubmitSuggestions(); 160 // is disabled this will never happen, so offline pages are fetched here
161 // instead.
162 AsynchronouslyFetchOfflinePagesDownloads(/*notify=*/true);
163 }
159 } 164 }
160 165
161 DownloadSuggestionsProvider::~DownloadSuggestionsProvider() { 166 DownloadSuggestionsProvider::~DownloadSuggestionsProvider() {
162 if (offline_page_model_) { 167 if (offline_page_model_) {
163 offline_page_model_->RemoveObserver(this); 168 offline_page_model_->RemoveObserver(this);
164 } 169 }
165 170
166 if (download_manager_) { 171 if (download_manager_) {
167 download_manager_->RemoveObserver(this); 172 download_manager_->RemoveObserver(this);
168 UnregisterDownloadItemObservers(); 173 UnregisterDownloadItemObservers();
169 } 174 }
175
176 if (download_history_) {
177 download_history_->RemoveObserver(this);
178 }
170 } 179 }
171 180
172 CategoryStatus DownloadSuggestionsProvider::GetCategoryStatus( 181 CategoryStatus DownloadSuggestionsProvider::GetCategoryStatus(
173 Category category) { 182 Category category) {
174 DCHECK_EQ(provided_category_, category); 183 DCHECK_EQ(provided_category_, category);
175 return category_status_; 184 return category_status_;
176 } 185 }
177 186
178 CategoryInfo DownloadSuggestionsProvider::GetCategoryInfo(Category category) { 187 CategoryInfo DownloadSuggestionsProvider::GetCategoryInfo(Category category) {
179 DCHECK_EQ(provided_category_, category); 188 DCHECK_EQ(provided_category_, category);
180 return CategoryInfo( 189 return CategoryInfo(
181 l10n_util::GetStringUTF16(IDS_NTP_DOWNLOAD_SUGGESTIONS_SECTION_HEADER), 190 l10n_util::GetStringUTF16(IDS_NTP_DOWNLOAD_SUGGESTIONS_SECTION_HEADER),
182 ntp_snippets::ContentSuggestionsCardLayout::MINIMAL_CARD, 191 ntp_snippets::ContentSuggestionsCardLayout::MINIMAL_CARD,
183 /*has_more_action=*/false, 192 /*has_more_action=*/false,
184 /*has_reload_action=*/false, 193 /*has_reload_action=*/false,
185 /*has_view_all_action=*/download_manager_ui_enabled_, 194 /*has_view_all_action=*/download_manager_ui_enabled_,
186 /*show_if_empty=*/false, 195 /*show_if_empty=*/false,
187 l10n_util::GetStringUTF16(IDS_NTP_DOWNLOADS_SUGGESTIONS_SECTION_EMPTY)); 196 l10n_util::GetStringUTF16(IDS_NTP_DOWNLOADS_SUGGESTIONS_SECTION_EMPTY));
188 } 197 }
189 198
190 void DownloadSuggestionsProvider::DismissSuggestion( 199 void DownloadSuggestionsProvider::DismissSuggestion(
191 const ContentSuggestion::ID& suggestion_id) { 200 const ContentSuggestion::ID& suggestion_id) {
192 DCHECK_EQ(provided_category_, suggestion_id.category()); 201 DCHECK_EQ(provided_category_, suggestion_id.category());
202 std::set<std::string> dismissed_ids =
203 ReadDismissedIDsFromPrefs(CorrespondsToOfflinePage(suggestion_id));
204 dismissed_ids.insert(suggestion_id.id_within_category());
205 StoreDismissedIDsToPrefs(CorrespondsToOfflinePage(suggestion_id),
206 dismissed_ids);
193 207
194 AddToDismissedStorageIfNeeded(suggestion_id);
195 RemoveSuggestionFromCacheAndRetrieveMoreIfNeeded(suggestion_id); 208 RemoveSuggestionFromCacheAndRetrieveMoreIfNeeded(suggestion_id);
196 } 209 }
197 210
198 void DownloadSuggestionsProvider::FetchSuggestionImage( 211 void DownloadSuggestionsProvider::FetchSuggestionImage(
199 const ContentSuggestion::ID& suggestion_id, 212 const ContentSuggestion::ID& suggestion_id,
200 const ntp_snippets::ImageFetchedCallback& callback) { 213 const ntp_snippets::ImageFetchedCallback& callback) {
201 // TODO(vitaliii): Fetch proper thumbnail from OfflinePageModel once it is 214 // TODO(vitaliii): Fetch proper thumbnail from OfflinePageModel once it is
202 // available there. 215 // available there.
203 // TODO(vitaliii): Provide site's favicon for assets downloads or file type. 216 // TODO(vitaliii): Provide site's favicon for assets downloads or file type.
204 // See crbug.com/631447. 217 // See crbug.com/631447.
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 weak_ptr_factory_.GetWeakPtr(), callback)); 268 weak_ptr_factory_.GetWeakPtr(), callback));
256 } else { 269 } else {
257 GetPagesMatchingQueryCallbackForGetDismissedSuggestions( 270 GetPagesMatchingQueryCallbackForGetDismissedSuggestions(
258 callback, std::vector<OfflinePageItem>()); 271 callback, std::vector<OfflinePageItem>());
259 } 272 }
260 } 273 }
261 274
262 void DownloadSuggestionsProvider::ClearDismissedSuggestionsForDebugging( 275 void DownloadSuggestionsProvider::ClearDismissedSuggestionsForDebugging(
263 Category category) { 276 Category category) {
264 DCHECK_EQ(provided_category_, category); 277 DCHECK_EQ(provided_category_, category);
265 StoreAssetDismissedIDsToPrefs(std::vector<std::string>()); 278 StoreAssetDismissedIDsToPrefs(std::set<std::string>());
266 StoreOfflinePageDismissedIDsToPrefs(std::set<std::string>()); 279 StoreOfflinePageDismissedIDsToPrefs(std::set<std::string>());
267 AsynchronouslyFetchAllDownloadsAndSubmitSuggestions(); 280 AsynchronouslyFetchAllDownloadsAndSubmitSuggestions();
268 } 281 }
269 282
270 // static 283 // static
271 void DownloadSuggestionsProvider::RegisterProfilePrefs( 284 void DownloadSuggestionsProvider::RegisterProfilePrefs(
272 PrefRegistrySimple* registry) { 285 PrefRegistrySimple* registry) {
273 registry->RegisterListPref(kDismissedAssetDownloadSuggestions); 286 registry->RegisterListPref(kDismissedAssetDownloadSuggestions);
274 registry->RegisterListPref(kDismissedOfflinePageDownloadSuggestions); 287 registry->RegisterListPref(kDismissedOfflinePageDownloadSuggestions);
275 } 288 }
276 289
277 int DownloadSuggestionsProvider::GetMaxDismissedCountForTesting() {
278 return kMaxDismissedIdCount;
279 }
280
281 //////////////////////////////////////////////////////////////////////////////// 290 ////////////////////////////////////////////////////////////////////////////////
282 // Private methods 291 // Private methods
283 292
284 void DownloadSuggestionsProvider:: 293 void DownloadSuggestionsProvider::
285 GetPagesMatchingQueryCallbackForGetDismissedSuggestions( 294 GetPagesMatchingQueryCallbackForGetDismissedSuggestions(
286 const ntp_snippets::DismissedSuggestionsCallback& callback, 295 const ntp_snippets::DismissedSuggestionsCallback& callback,
287 const std::vector<OfflinePageItem>& offline_pages) const { 296 const std::vector<OfflinePageItem>& offline_pages) const {
288 std::set<std::string> dismissed_offline_ids = 297 std::set<std::string> dismissed_ids = ReadOfflinePageDismissedIDsFromPrefs();
289 ReadOfflinePageDismissedIDsFromPrefs();
290 std::vector<ContentSuggestion> suggestions; 298 std::vector<ContentSuggestion> suggestions;
291 for (const OfflinePageItem& item : offline_pages) { 299 for (const OfflinePageItem& item : offline_pages) {
292 if (dismissed_offline_ids.count( 300 if (dismissed_ids.count(GetOfflinePagePerCategoryID(item.offline_id))) {
293 GetOfflinePagePerCategoryID(item.offline_id))) {
294 suggestions.push_back(ConvertOfflinePage(item)); 301 suggestions.push_back(ConvertOfflinePage(item));
295 } 302 }
296 } 303 }
297 304
298 if (download_manager_) { 305 if (download_manager_) {
299 std::vector<DownloadItem*> all_downloads; 306 std::vector<DownloadItem*> all_downloads;
300 download_manager_->GetAllDownloads(&all_downloads); 307 download_manager_->GetAllDownloads(&all_downloads);
301 308
302 std::vector<std::string> dismissed_asset_ids = 309 dismissed_ids = ReadAssetDismissedIDsFromPrefs();
303 ReadAssetDismissedIDsFromPrefs();
304 310
305 for (const DownloadItem* item : all_downloads) { 311 for (const DownloadItem* item : all_downloads) {
306 if (ContainsValue(dismissed_asset_ids, 312 if (dismissed_ids.count(GetAssetDownloadPerCategoryID(item->GetId()))) {
307 GetAssetDownloadPerCategoryID(item->GetId()))) {
308 suggestions.push_back(ConvertDownloadItem(*item)); 313 suggestions.push_back(ConvertDownloadItem(*item));
309 } 314 }
310 } 315 }
311 } 316 }
312 317
313 callback.Run(std::move(suggestions)); 318 callback.Run(std::move(suggestions));
314 } 319 }
315 320
316 void DownloadSuggestionsProvider::OfflinePageModelLoaded( 321 void DownloadSuggestionsProvider::OfflinePageModelLoaded(
317 offline_pages::OfflinePageModel* model) { 322 offline_pages::OfflinePageModel* model) {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 DCHECK(offline_page_model_); 360 DCHECK(offline_page_model_);
356 if (IsClientIdForOfflinePageDownload( 361 if (IsClientIdForOfflinePageDownload(
357 offline_page_model_->GetPolicyController(), client_id)) { 362 offline_page_model_->GetPolicyController(), client_id)) {
358 InvalidateSuggestion(GetOfflinePagePerCategoryID(offline_id)); 363 InvalidateSuggestion(GetOfflinePagePerCategoryID(offline_id));
359 } 364 }
360 } 365 }
361 366
362 void DownloadSuggestionsProvider::OnDownloadCreated(DownloadManager* manager, 367 void DownloadSuggestionsProvider::OnDownloadCreated(DownloadManager* manager,
363 DownloadItem* item) { 368 DownloadItem* item) {
364 DCHECK_EQ(download_manager_, manager); 369 DCHECK_EQ(download_manager_, manager);
370
371 if (!is_download_manager_loaded_) {
372 // This notification is ignored before the manager is loaded, because all
373 // downloads will be queried once it is loaded.
374 return;
375 }
376
365 // This is called when new downloads are started and on startup for existing 377 // This is called when new downloads are started and on startup for existing
366 // ones. We listen to each item to know when it is destroyed. 378 // ones. We listen to each item to know when it is destroyed.
367 item->AddObserver(this); 379 item->AddObserver(this);
368 if (CacheAssetDownloadIfNeeded(item)) { 380 if (CacheAssetDownloadIfNeeded(item)) {
369 SubmitContentSuggestions(); 381 SubmitContentSuggestions();
370 } 382 }
371 } 383 }
372 384
373 void DownloadSuggestionsProvider::ManagerGoingDown(DownloadManager* manager) { 385 void DownloadSuggestionsProvider::ManagerGoingDown(DownloadManager* manager) {
374 DCHECK_EQ(download_manager_, manager); 386 DCHECK_EQ(download_manager_, manager);
375 UnregisterDownloadItemObservers(); 387 UnregisterDownloadItemObservers();
376 download_manager_ = nullptr; 388 download_manager_ = nullptr;
389 if (download_history_) {
390 download_history_->RemoveObserver(this);
391 download_history_ = nullptr;
392 }
377 } 393 }
378 394
379 void DownloadSuggestionsProvider::OnDownloadUpdated(DownloadItem* item) { 395 void DownloadSuggestionsProvider::OnDownloadUpdated(DownloadItem* item) {
380 if (ContainsValue(cached_asset_downloads_, item)) { 396 DCHECK(is_download_manager_loaded_);
397 if (base::ContainsValue(cached_asset_downloads_, item)) {
381 if (item->GetFileExternallyRemoved()) { 398 if (item->GetFileExternallyRemoved()) {
382 InvalidateSuggestion(GetAssetDownloadPerCategoryID(item->GetId())); 399 InvalidateSuggestion(GetAssetDownloadPerCategoryID(item->GetId()));
383 } else { 400 } else {
384 // The download may have changed. 401 // The download may have changed.
385 SubmitContentSuggestions(); 402 SubmitContentSuggestions();
386 } 403 }
387 } else { 404 } else {
388 // Unfinished downloads may become completed. 405 // Unfinished downloads may become completed.
389 if (CacheAssetDownloadIfNeeded(item)) { 406 if (CacheAssetDownloadIfNeeded(item)) {
390 SubmitContentSuggestions(); 407 SubmitContentSuggestions();
391 } 408 }
392 } 409 }
393 } 410 }
394 411
395 void DownloadSuggestionsProvider::OnDownloadOpened(DownloadItem* item) { 412 void DownloadSuggestionsProvider::OnDownloadOpened(DownloadItem* item) {
396 // Ignored. 413 // Ignored.
397 } 414 }
398 415
399 void DownloadSuggestionsProvider::OnDownloadRemoved(DownloadItem* item) { 416 void DownloadSuggestionsProvider::OnDownloadRemoved(DownloadItem* item) {
400 // Ignored. We listen to |OnDownloadDestroyed| instead. The reason is that 417 // Ignored. We listen to |OnDownloadDestroyed| instead. The reason is that
401 // we may need to retrieve all downloads, but |OnDownloadRemoved| is called 418 // we may need to retrieve all downloads, but |OnDownloadRemoved| is called
402 // before the download is removed from the list. 419 // before the download is removed from the list.
403 } 420 }
404 421
405 void DownloadSuggestionsProvider::OnDownloadDestroyed( 422 void DownloadSuggestionsProvider::OnDownloadDestroyed(
406 content::DownloadItem* item) { 423 content::DownloadItem* item) {
424 DCHECK(is_download_manager_loaded_);
425
407 item->RemoveObserver(this); 426 item->RemoveObserver(this);
408 427
409 if (!IsDownloadCompleted(*item)) { 428 if (!IsDownloadCompleted(*item)) {
410 return; 429 return;
411 } 430 }
412 // TODO(vitaliii): Implement a better way to clean up dismissed IDs (in case 431 // TODO(vitaliii): Implement a better way to clean up dismissed IDs (in case
413 // some calls are missed). 432 // some calls are missed).
414 InvalidateSuggestion(GetAssetDownloadPerCategoryID(item->GetId())); 433 InvalidateSuggestion(GetAssetDownloadPerCategoryID(item->GetId()));
415 } 434 }
416 435
436 void DownloadSuggestionsProvider::OnHistoryQueryComplete() {
437 is_download_manager_loaded_ = true;
438 AsynchronouslyFetchAllDownloadsAndSubmitSuggestions();
439 }
440
441 void DownloadSuggestionsProvider::OnDownloadHistoryDestroyed() {
442 DCHECK(download_history_);
443 download_history_->RemoveObserver(this);
444 download_history_ = nullptr;
445 }
446
417 void DownloadSuggestionsProvider::NotifyStatusChanged( 447 void DownloadSuggestionsProvider::NotifyStatusChanged(
418 CategoryStatus new_status) { 448 CategoryStatus new_status) {
419 DCHECK_NE(CategoryStatus::NOT_PROVIDED, category_status_); 449 DCHECK_NE(CategoryStatus::NOT_PROVIDED, category_status_);
420 DCHECK_NE(CategoryStatus::NOT_PROVIDED, new_status); 450 DCHECK_NE(CategoryStatus::NOT_PROVIDED, new_status);
421 if (category_status_ == new_status) { 451 if (category_status_ == new_status) {
422 return; 452 return;
423 } 453 }
424 category_status_ = new_status; 454 category_status_ = new_status;
425 observer()->OnCategoryStatusChanged(this, provided_category_, 455 observer()->OnCategoryStatusChanged(this, provided_category_,
426 category_status_); 456 category_status_);
(...skipping 24 matching lines...) Expand all
451 } 481 }
452 482
453 void DownloadSuggestionsProvider::FetchAssetsDownloads() { 483 void DownloadSuggestionsProvider::FetchAssetsDownloads() {
454 if (!download_manager_) { 484 if (!download_manager_) {
455 // The manager has gone down or was explicitly turned off. 485 // The manager has gone down or was explicitly turned off.
456 return; 486 return;
457 } 487 }
458 488
459 std::vector<DownloadItem*> all_downloads; 489 std::vector<DownloadItem*> all_downloads;
460 download_manager_->GetAllDownloads(&all_downloads); 490 download_manager_->GetAllDownloads(&all_downloads);
461 std::vector<std::string> old_dismissed_ids = ReadAssetDismissedIDsFromPrefs(); 491 std::set<std::string> old_dismissed_ids = ReadAssetDismissedIDsFromPrefs();
492 std::set<std::string> retained_dismissed_ids;
462 cached_asset_downloads_.clear(); 493 cached_asset_downloads_.clear();
463 for (const DownloadItem* item : all_downloads) { 494 for (DownloadItem* item : all_downloads) {
464 std::string within_category_id = 495 std::string within_category_id =
465 GetAssetDownloadPerCategoryID(item->GetId()); 496 GetAssetDownloadPerCategoryID(item->GetId());
466 if (!ContainsValue(old_dismissed_ids, within_category_id)) { 497 if (!old_dismissed_ids.count(within_category_id)) {
467 if (IsDownloadCompleted(*item)) { 498 if (IsDownloadCompleted(*item)) {
468 cached_asset_downloads_.push_back(item); 499 cached_asset_downloads_.push_back(item);
500 item->RemoveObserver(this);
tschumann 2017/01/12 11:06:09 what is this doing? Which role is 'this' playing h
vitaliii 2017/01/16 08:51:35 This prevents adding this class as observer twice
tschumann 2017/01/16 09:14:05 =) A comment explaining this briefly would be grea
Marc Treib 2017/01/16 10:33:05 Yup - please at least add a comment for now, and l
vitaliii 2017/01/16 14:32:39 Done. I added a comment about RemoveObserver.
501 item->AddObserver(this);
469 } 502 }
503 } else {
504 retained_dismissed_ids.insert(within_category_id);
470 } 505 }
471 } 506 }
472 507
473 // We do not prune dismissed IDs, because it is not possible to ensure that 508 if (old_dismissed_ids.size() != retained_dismissed_ids.size()) {
474 // the list of downloads is complete (i.e. DownloadManager has finished 509 StoreAssetDismissedIDsToPrefs(retained_dismissed_ids);
475 // reading them). 510 }
476 // TODO(vitaliii): Prune dismissed IDs once the |OnLoaded| notification is 511
477 // provided. See crbug.com/672758.
478 const int max_suggestions_count = GetMaxSuggestionsCount(); 512 const int max_suggestions_count = GetMaxSuggestionsCount();
479 if (static_cast<int>(cached_asset_downloads_.size()) > 513 if (static_cast<int>(cached_asset_downloads_.size()) >
480 max_suggestions_count) { 514 max_suggestions_count) {
481 // Partially sorts |downloads| such that: 515 // Partially sorts |downloads| such that:
482 // 1) The element at the index |max_suggestions_count| is changed to the 516 // 1) The element at the index |max_suggestions_count| is changed to the
483 // element which would occur on this position if |downloads| was sorted; 517 // element which would occur on this position if |downloads| was sorted;
484 // 2) All of the elements before index |max_suggestions_count| are less than 518 // 2) All of the elements before index |max_suggestions_count| are less than
485 // or equal to the elements after it. 519 // or equal to the elements after it.
486 std::nth_element(cached_asset_downloads_.begin(), 520 std::nth_element(cached_asset_downloads_.begin(),
487 cached_asset_downloads_.begin() + max_suggestions_count, 521 cached_asset_downloads_.begin() + max_suggestions_count,
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
565 suggestion.set_download_suggestion_extra(std::move(extra)); 599 suggestion.set_download_suggestion_extra(std::move(extra));
566 return suggestion; 600 return suggestion;
567 } 601 }
568 602
569 bool DownloadSuggestionsProvider::CacheAssetDownloadIfNeeded( 603 bool DownloadSuggestionsProvider::CacheAssetDownloadIfNeeded(
570 const content::DownloadItem* item) { 604 const content::DownloadItem* item) {
571 if (!IsDownloadCompleted(*item)) { 605 if (!IsDownloadCompleted(*item)) {
572 return false; 606 return false;
573 } 607 }
574 608
575 if (ContainsValue(cached_asset_downloads_, item)) { 609 if (base::ContainsValue(cached_asset_downloads_, item)) {
576 return false; 610 return false;
577 } 611 }
578 612
579 std::vector<std::string> dismissed_ids = ReadAssetDismissedIDsFromPrefs(); 613 std::set<std::string> dismissed_ids = ReadAssetDismissedIDsFromPrefs();
580 if (ContainsValue(dismissed_ids, 614 if (dismissed_ids.count(GetAssetDownloadPerCategoryID(item->GetId()))) {
581 GetAssetDownloadPerCategoryID(item->GetId()))) {
582 return false; 615 return false;
583 } 616 }
584 617
585 DCHECK_LE(static_cast<int>(cached_asset_downloads_.size()), 618 DCHECK_LE(static_cast<int>(cached_asset_downloads_.size()),
586 GetMaxSuggestionsCount()); 619 GetMaxSuggestionsCount());
587 if (static_cast<int>(cached_asset_downloads_.size()) == 620 if (static_cast<int>(cached_asset_downloads_.size()) ==
588 GetMaxSuggestionsCount()) { 621 GetMaxSuggestionsCount()) {
589 auto oldest = std::max_element( 622 auto oldest = std::max_element(
590 cached_asset_downloads_.begin(), cached_asset_downloads_.end(), 623 cached_asset_downloads_.begin(), cached_asset_downloads_.end(),
591 &CompareDownloadsMostRecentlyDownloadedFirst); 624 &CompareDownloadsMostRecentlyDownloadedFirst);
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
709 if (notify) { 742 if (notify) {
710 SubmitContentSuggestions(); 743 SubmitContentSuggestions();
711 } 744 }
712 } 745 }
713 746
714 void DownloadSuggestionsProvider::InvalidateSuggestion( 747 void DownloadSuggestionsProvider::InvalidateSuggestion(
715 const std::string& id_within_category) { 748 const std::string& id_within_category) {
716 ContentSuggestion::ID suggestion_id(provided_category_, id_within_category); 749 ContentSuggestion::ID suggestion_id(provided_category_, id_within_category);
717 observer()->OnSuggestionInvalidated(this, suggestion_id); 750 observer()->OnSuggestionInvalidated(this, suggestion_id);
718 751
719 RemoveFromDismissedStorageIfNeeded(suggestion_id); 752 std::set<std::string> dismissed_ids =
753 ReadDismissedIDsFromPrefs(CorrespondsToOfflinePage(suggestion_id));
754 auto it = dismissed_ids.find(id_within_category);
755 if (it != dismissed_ids.end()) {
756 dismissed_ids.erase(it);
757 StoreDismissedIDsToPrefs(CorrespondsToOfflinePage(suggestion_id),
758 dismissed_ids);
759 }
760
720 RemoveSuggestionFromCacheAndRetrieveMoreIfNeeded(suggestion_id); 761 RemoveSuggestionFromCacheAndRetrieveMoreIfNeeded(suggestion_id);
721 } 762 }
722 763
723 // TODO(vitaliii): Do not use std::vector, when we ensure that pruning happens 764 std::set<std::string>
724 // at the right time (crbug.com/672758).
725 std::vector<std::string>
726 DownloadSuggestionsProvider::ReadAssetDismissedIDsFromPrefs() const { 765 DownloadSuggestionsProvider::ReadAssetDismissedIDsFromPrefs() const {
727 std::vector<std::string> dismissed_ids; 766 return ntp_snippets::prefs::ReadDismissedIDsFromPrefs(
728 const base::ListValue* list = 767 *pref_service_, kDismissedAssetDownloadSuggestions);
729 pref_service_->GetList(kDismissedAssetDownloadSuggestions);
730 for (const std::unique_ptr<base::Value>& value : *list) {
731 std::string dismissed_id;
732 bool success = value->GetAsString(&dismissed_id);
733 DCHECK(success) << "Failed to parse dismissed id from prefs param "
734 << kDismissedAssetDownloadSuggestions << " into string.";
735 dismissed_ids.push_back(dismissed_id);
736 }
737 return dismissed_ids;
738 } 768 }
739 769
740 void DownloadSuggestionsProvider::StoreAssetDismissedIDsToPrefs( 770 void DownloadSuggestionsProvider::StoreAssetDismissedIDsToPrefs(
741 const std::vector<std::string>& dismissed_ids) { 771 const std::set<std::string>& dismissed_ids) {
742 DCHECK(std::all_of( 772 DCHECK(std::all_of(
743 dismissed_ids.begin(), dismissed_ids.end(), 773 dismissed_ids.begin(), dismissed_ids.end(),
744 [](const std::string& id) { return id[0] == kAssetDownloadsPrefix; })); 774 [](const std::string& id) { return id[0] == kAssetDownloadsPrefix; }));
745 775 ntp_snippets::prefs::StoreDismissedIDsToPrefs(
746 base::ListValue list; 776 pref_service_, kDismissedAssetDownloadSuggestions, dismissed_ids);
747 for (const std::string& dismissed_id : dismissed_ids) {
748 list.AppendString(dismissed_id);
749 }
750 pref_service_->Set(kDismissedAssetDownloadSuggestions, list);
751 } 777 }
752 778
753 std::set<std::string> 779 std::set<std::string>
754 DownloadSuggestionsProvider::ReadOfflinePageDismissedIDsFromPrefs() const { 780 DownloadSuggestionsProvider::ReadOfflinePageDismissedIDsFromPrefs() const {
755 return ntp_snippets::prefs::ReadDismissedIDsFromPrefs( 781 return ntp_snippets::prefs::ReadDismissedIDsFromPrefs(
756 *pref_service_, kDismissedOfflinePageDownloadSuggestions); 782 *pref_service_, kDismissedOfflinePageDownloadSuggestions);
757 } 783 }
758 784
759 void DownloadSuggestionsProvider::StoreOfflinePageDismissedIDsToPrefs( 785 void DownloadSuggestionsProvider::StoreOfflinePageDismissedIDsToPrefs(
760 const std::set<std::string>& dismissed_ids) { 786 const std::set<std::string>& dismissed_ids) {
761 DCHECK(std::all_of(dismissed_ids.begin(), dismissed_ids.end(), 787 DCHECK(std::all_of(dismissed_ids.begin(), dismissed_ids.end(),
762 [](const std::string& id) { 788 [](const std::string& id) {
763 return id[0] == kOfflinePageDownloadsPrefix; 789 return id[0] == kOfflinePageDownloadsPrefix;
764 })); 790 }));
765 ntp_snippets::prefs::StoreDismissedIDsToPrefs( 791 ntp_snippets::prefs::StoreDismissedIDsToPrefs(
766 pref_service_, kDismissedOfflinePageDownloadSuggestions, dismissed_ids); 792 pref_service_, kDismissedOfflinePageDownloadSuggestions, dismissed_ids);
767 } 793 }
768 794
769 void DownloadSuggestionsProvider::AddToDismissedStorageIfNeeded( 795 std::set<std::string> DownloadSuggestionsProvider::ReadDismissedIDsFromPrefs(
770 const ContentSuggestion::ID& suggestion_id) { 796 bool for_offline_page_downloads) const {
771 if (CorrespondsToOfflinePage(suggestion_id)) { 797 if (for_offline_page_downloads) {
772 std::set<std::string> dismissed_ids = 798 return ReadOfflinePageDismissedIDsFromPrefs();
773 ReadOfflinePageDismissedIDsFromPrefs(); 799 }
774 dismissed_ids.insert(suggestion_id.id_within_category()); 800 return ReadAssetDismissedIDsFromPrefs();
801 }
802
803 void DownloadSuggestionsProvider::StoreDismissedIDsToPrefs(
804 bool for_offline_page_downloads,
805 const std::set<std::string>& dismissed_ids) {
806 if (for_offline_page_downloads) {
775 StoreOfflinePageDismissedIDsToPrefs(dismissed_ids); 807 StoreOfflinePageDismissedIDsToPrefs(dismissed_ids);
776 } else { 808 } else {
777 std::vector<std::string> dismissed_ids = ReadAssetDismissedIDsFromPrefs(); 809 StoreAssetDismissedIDsToPrefs(dismissed_ids);
778 // The suggestion may be double dismissed from previously opened NTPs.
779 if (!ContainsValue(dismissed_ids, suggestion_id.id_within_category())) {
780 dismissed_ids.push_back(suggestion_id.id_within_category());
781 // TODO(vitaliii): Remove this workaround once the dismissed ids are
782 // pruned. See crbug.com/672758.
783 while (dismissed_ids.size() > kMaxDismissedIdCount) {
784 dismissed_ids.erase(dismissed_ids.begin());
785 }
786 StoreAssetDismissedIDsToPrefs(dismissed_ids);
787 }
788 } 810 }
789 } 811 }
790 812
791 void DownloadSuggestionsProvider::RemoveFromDismissedStorageIfNeeded(
792 const ContentSuggestion::ID& suggestion_id) {
793 if (CorrespondsToOfflinePage(suggestion_id)) {
794 std::set<std::string> dismissed_ids =
795 ReadOfflinePageDismissedIDsFromPrefs();
796 if (dismissed_ids.count(suggestion_id.id_within_category())) {
797 dismissed_ids.erase(suggestion_id.id_within_category());
798 StoreOfflinePageDismissedIDsToPrefs(dismissed_ids);
799 }
800 } else {
801 std::vector<std::string> dismissed_ids = ReadAssetDismissedIDsFromPrefs();
802 auto it = std::find(dismissed_ids.begin(), dismissed_ids.end(),
803 suggestion_id.id_within_category());
804 if (it != dismissed_ids.end()) {
805 dismissed_ids.erase(it);
806 StoreAssetDismissedIDsToPrefs(dismissed_ids);
807 }
808 }
809 }
810
811 void DownloadSuggestionsProvider::UnregisterDownloadItemObservers() { 813 void DownloadSuggestionsProvider::UnregisterDownloadItemObservers() {
812 DCHECK_NE(download_manager_, nullptr); 814 DCHECK_NE(download_manager_, nullptr);
813 815
814 std::vector<DownloadItem*> all_downloads; 816 std::vector<DownloadItem*> all_downloads;
815 download_manager_->GetAllDownloads(&all_downloads); 817 download_manager_->GetAllDownloads(&all_downloads);
816 818
817 for (DownloadItem* item : all_downloads) { 819 for (DownloadItem* item : all_downloads) {
818 item->RemoveObserver(this); 820 item->RemoveObserver(this);
819 } 821 }
820 } 822 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698