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

Side by Side Diff: components/ntp_snippets/remote/remote_suggestions_provider.cc

Issue 2557363002: [NTP Snippets] Refactor background scheduling for remote suggestions (Closed)
Patch Set: Rebase Created 4 years 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 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/ntp_snippets/remote/remote_suggestions_provider.h" 5 #include "components/ntp_snippets/remote/remote_suggestions_provider.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <iterator> 8 #include <iterator>
9 #include <utility> 9 #include <utility>
10 10
(...skipping 13 matching lines...) Expand all
24 #include "base/time/time.h" 24 #include "base/time/time.h"
25 #include "base/values.h" 25 #include "base/values.h"
26 #include "components/data_use_measurement/core/data_use_user_data.h" 26 #include "components/data_use_measurement/core/data_use_user_data.h"
27 #include "components/history/core/browser/history_service.h" 27 #include "components/history/core/browser/history_service.h"
28 #include "components/image_fetcher/image_decoder.h" 28 #include "components/image_fetcher/image_decoder.h"
29 #include "components/image_fetcher/image_fetcher.h" 29 #include "components/image_fetcher/image_fetcher.h"
30 #include "components/ntp_snippets/features.h" 30 #include "components/ntp_snippets/features.h"
31 #include "components/ntp_snippets/pref_names.h" 31 #include "components/ntp_snippets/pref_names.h"
32 #include "components/ntp_snippets/remote/remote_suggestions_database.h" 32 #include "components/ntp_snippets/remote/remote_suggestions_database.h"
33 #include "components/ntp_snippets/switches.h" 33 #include "components/ntp_snippets/switches.h"
34 #include "components/ntp_snippets/user_classifier.h"
35 #include "components/prefs/pref_registry_simple.h" 34 #include "components/prefs/pref_registry_simple.h"
36 #include "components/prefs/pref_service.h" 35 #include "components/prefs/pref_service.h"
37 #include "components/variations/variations_associated_data.h" 36 #include "components/variations/variations_associated_data.h"
38 #include "grit/components_strings.h" 37 #include "grit/components_strings.h"
39 #include "ui/base/l10n/l10n_util.h" 38 #include "ui/base/l10n/l10n_util.h"
40 #include "ui/gfx/image/image.h" 39 #include "ui/gfx/image/image.h"
41 40
42 namespace ntp_snippets { 41 namespace ntp_snippets {
43 42
44 namespace { 43 namespace {
45 44
46 // Number of snippets requested to the server. Consider replacing sparse UMA 45 // Number of snippets requested to the server. Consider replacing sparse UMA
47 // histograms with COUNTS() if this number increases beyond 50. 46 // histograms with COUNTS() if this number increases beyond 50.
48 const int kMaxSnippetCount = 10; 47 const int kMaxSnippetCount = 10;
49 48
50 // Number of archived snippets we keep around in memory. 49 // Number of archived snippets we keep around in memory.
51 const int kMaxArchivedSnippetCount = 200; 50 const int kMaxArchivedSnippetCount = 200;
52 51
53 // Default values for fetching intervals, fallback and wifi.
54 const double kDefaultFetchingIntervalRareNtpUser[] = {48.0, 24.0};
55 const double kDefaultFetchingIntervalActiveNtpUser[] = {24.0, 6.0};
56 const double kDefaultFetchingIntervalActiveSuggestionsConsumer[] = {24.0, 6.0};
57
58 // Variation parameters than can override the default fetching intervals.
59 const char* kFetchingIntervalParamNameRareNtpUser[] = {
60 "fetching_interval_hours-fallback-rare_ntp_user",
61 "fetching_interval_hours-wifi-rare_ntp_user"};
62 const char* kFetchingIntervalParamNameActiveNtpUser[] = {
63 "fetching_interval_hours-fallback-active_ntp_user",
64 "fetching_interval_hours-wifi-active_ntp_user"};
65 const char* kFetchingIntervalParamNameActiveSuggestionsConsumer[] = {
66 "fetching_interval_hours-fallback-active_suggestions_consumer",
67 "fetching_interval_hours-wifi-active_suggestions_consumer"};
68
69 // Keys for storing CategoryContent info in prefs. 52 // Keys for storing CategoryContent info in prefs.
70 const char kCategoryContentId[] = "id"; 53 const char kCategoryContentId[] = "id";
71 const char kCategoryContentTitle[] = "title"; 54 const char kCategoryContentTitle[] = "title";
72 const char kCategoryContentProvidedByServer[] = "provided_by_server"; 55 const char kCategoryContentProvidedByServer[] = "provided_by_server";
73 const char kCategoryContentAllowFetchingMore[] = "allow_fetching_more"; 56 const char kCategoryContentAllowFetchingMore[] = "allow_fetching_more";
74 57
75 // TODO(treib): Remove after M57. 58 // TODO(treib): Remove after M57.
76 const char kDeprecatedSnippetHostsPref[] = "ntp_snippets.hosts"; 59 const char kDeprecatedSnippetHostsPref[] = "ntp_snippets.hosts";
77 60
78 base::TimeDelta GetFetchingInterval(bool is_wifi,
79 UserClassifier::UserClass user_class) {
80 double value_hours = 0.0;
81
82 const int index = is_wifi ? 1 : 0;
83 const char* param_name = "";
84 switch (user_class) {
85 case UserClassifier::UserClass::RARE_NTP_USER:
86 value_hours = kDefaultFetchingIntervalRareNtpUser[index];
87 param_name = kFetchingIntervalParamNameRareNtpUser[index];
88 break;
89 case UserClassifier::UserClass::ACTIVE_NTP_USER:
90 value_hours = kDefaultFetchingIntervalActiveNtpUser[index];
91 param_name = kFetchingIntervalParamNameActiveNtpUser[index];
92 break;
93 case UserClassifier::UserClass::ACTIVE_SUGGESTIONS_CONSUMER:
94 value_hours = kDefaultFetchingIntervalActiveSuggestionsConsumer[index];
95 param_name = kFetchingIntervalParamNameActiveSuggestionsConsumer[index];
96 break;
97 }
98
99 // The default value can be overridden by a variation parameter.
100 std::string param_value_str = variations::GetVariationParamValueByFeature(
101 ntp_snippets::kArticleSuggestionsFeature, param_name);
102 if (!param_value_str.empty()) {
103 double param_value_hours = 0.0;
104 if (base::StringToDouble(param_value_str, &param_value_hours)) {
105 value_hours = param_value_hours;
106 } else {
107 LOG(WARNING) << "Invalid value for variation parameter " << param_name;
108 }
109 }
110
111 return base::TimeDelta::FromSecondsD(value_hours * 3600.0);
112 }
113
114 std::unique_ptr<std::vector<std::string>> GetSnippetIDVector( 61 std::unique_ptr<std::vector<std::string>> GetSnippetIDVector(
115 const NTPSnippet::PtrVector& snippets) { 62 const NTPSnippet::PtrVector& snippets) {
116 auto result = base::MakeUnique<std::vector<std::string>>(); 63 auto result = base::MakeUnique<std::vector<std::string>>();
117 for (const auto& snippet : snippets) { 64 for (const auto& snippet : snippets) {
118 result->push_back(snippet->id()); 65 result->push_back(snippet->id());
119 } 66 }
120 return result; 67 return result;
121 } 68 }
122 69
123 bool HasIntersection(const std::vector<std::string>& a, 70 bool HasIntersection(const std::vector<std::string>& a,
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 callback.Run(status, std::vector<ContentSuggestion>()); 167 callback.Run(status, std::vector<ContentSuggestion>());
221 } 168 }
222 169
223 } // namespace 170 } // namespace
224 171
225 RemoteSuggestionsProvider::RemoteSuggestionsProvider( 172 RemoteSuggestionsProvider::RemoteSuggestionsProvider(
226 Observer* observer, 173 Observer* observer,
227 CategoryFactory* category_factory, 174 CategoryFactory* category_factory,
228 PrefService* pref_service, 175 PrefService* pref_service,
229 const std::string& application_language_code, 176 const std::string& application_language_code,
230 const UserClassifier* user_classifier,
231 NTPSnippetsScheduler* scheduler,
232 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher, 177 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher,
233 std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher, 178 std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher,
234 std::unique_ptr<image_fetcher::ImageDecoder> image_decoder, 179 std::unique_ptr<image_fetcher::ImageDecoder> image_decoder,
235 std::unique_ptr<RemoteSuggestionsDatabase> database, 180 std::unique_ptr<RemoteSuggestionsDatabase> database,
236 std::unique_ptr<RemoteSuggestionsStatusService> status_service) 181 std::unique_ptr<RemoteSuggestionsStatusService> status_service)
237 : ContentSuggestionsProvider(observer, category_factory), 182 : ContentSuggestionsProvider(observer, category_factory),
238 state_(State::NOT_INITED), 183 state_(State::NOT_INITED),
239 pref_service_(pref_service), 184 pref_service_(pref_service),
240 articles_category_( 185 articles_category_(
241 category_factory->FromKnownCategory(KnownCategories::ARTICLES)), 186 category_factory->FromKnownCategory(KnownCategories::ARTICLES)),
242 application_language_code_(application_language_code), 187 application_language_code_(application_language_code),
243 user_classifier_(user_classifier),
244 scheduler_(scheduler),
245 snippets_fetcher_(std::move(snippets_fetcher)), 188 snippets_fetcher_(std::move(snippets_fetcher)),
246 image_fetcher_(std::move(image_fetcher)), 189 image_fetcher_(std::move(image_fetcher)),
247 image_decoder_(std::move(image_decoder)), 190 image_decoder_(std::move(image_decoder)),
248 database_(std::move(database)), 191 database_(std::move(database)),
249 status_service_(std::move(status_service)), 192 status_service_(std::move(status_service)),
250 fetch_when_ready_(false), 193 fetch_when_ready_(false),
194 fetch_when_ready_interactive_(false),
251 nuke_when_initialized_(false), 195 nuke_when_initialized_(false),
252 thumbnail_requests_throttler_( 196 thumbnail_requests_throttler_(
253 pref_service, 197 pref_service,
254 RequestThrottler::RequestType::CONTENT_SUGGESTION_THUMBNAIL), 198 RequestThrottler::RequestType::CONTENT_SUGGESTION_THUMBNAIL),
255 clock_(base::MakeUnique<base::DefaultClock>()) { 199 clock_(base::MakeUnique<base::DefaultClock>()) {
256 pref_service_->ClearPref(kDeprecatedSnippetHostsPref); 200 pref_service_->ClearPref(kDeprecatedSnippetHostsPref);
257 201
258 RestoreCategoriesFromPrefs(); 202 RestoreCategoriesFromPrefs();
259 // The articles category always exists. Add it if we didn't get it from prefs. 203 // The articles category always exists. Add it if we didn't get it from prefs.
260 // TODO(treib): Rethink this. 204 // TODO(treib): Rethink this.
(...skipping 22 matching lines...) Expand all
283 } 227 }
284 228
285 RemoteSuggestionsProvider::~RemoteSuggestionsProvider() = default; 229 RemoteSuggestionsProvider::~RemoteSuggestionsProvider() = default;
286 230
287 // static 231 // static
288 void RemoteSuggestionsProvider::RegisterProfilePrefs( 232 void RemoteSuggestionsProvider::RegisterProfilePrefs(
289 PrefRegistrySimple* registry) { 233 PrefRegistrySimple* registry) {
290 // TODO(treib): Remove after M57. 234 // TODO(treib): Remove after M57.
291 registry->RegisterListPref(kDeprecatedSnippetHostsPref); 235 registry->RegisterListPref(kDeprecatedSnippetHostsPref);
292 registry->RegisterListPref(prefs::kRemoteSuggestionCategories); 236 registry->RegisterListPref(prefs::kRemoteSuggestionCategories);
293 registry->RegisterInt64Pref(prefs::kSnippetBackgroundFetchingIntervalWifi, 0);
294 registry->RegisterInt64Pref(prefs::kSnippetBackgroundFetchingIntervalFallback,
295 0);
296 registry->RegisterInt64Pref(prefs::kLastSuccessfulBackgroundFetchTime, 0); 237 registry->RegisterInt64Pref(prefs::kLastSuccessfulBackgroundFetchTime, 0);
297 238
298 RemoteSuggestionsStatusService::RegisterProfilePrefs(registry); 239 RemoteSuggestionsStatusService::RegisterProfilePrefs(registry);
299 } 240 }
300 241
301 void RemoteSuggestionsProvider::FetchSnippetsInTheBackground() { 242 void RemoteSuggestionsProvider::RegisterActivenessObserver(
302 FetchSnippets(/*interactive_request=*/false); 243 const ProviderActiveCallback& callback) {
244 provider_active_callback_ = callback;
245
246 // Call the observer right away if we've reached any final state.
247 switch (state_) {
248 case State::NOT_INITED:
249 // Initial state, not sure yet whether active or not.
250 break;
251 case State::READY:
252 provider_active_callback_.Run(/*active=*/true);
253 break;
254 case State::DISABLED:
255 provider_active_callback_.Run(/*active=*/false);
256 break;
257 case State::ERROR_OCCURRED:
258 provider_active_callback_.Run(/*active=*/false);
259 break;
260 case State::COUNT:
261 NOTREACHED();
262 break;
263 }
303 } 264 }
304 265
305 void RemoteSuggestionsProvider::FetchSnippetsForAllCategories() { 266 void RemoteSuggestionsProvider::ReloadSuggestions() {
306 // TODO(markusheintz): Investigate whether we can call the Fetch method 267 FetchSnippets(/*interactive_request=*/true, FetchStatusCallback());
307 // instead of the FetchSnippets. 268 }
308 FetchSnippets(/*interactive_request=*/true); 269
270 void RemoteSuggestionsProvider::RefetchInTheBackground(
271 const FetchStatusCallback& callback) {
272 FetchSnippets(/*interactive_request=*/false, callback);
309 } 273 }
310 274
311 void RemoteSuggestionsProvider::FetchSnippets( 275 void RemoteSuggestionsProvider::FetchSnippets(
312 bool interactive_request) { 276 bool interactive_request,
277 const FetchStatusCallback& callback) {
313 if (!ready()) { 278 if (!ready()) {
314 fetch_when_ready_ = true; 279 fetch_when_ready_ = true;
315 return; 280 fetch_when_ready_interactive_ = interactive_request;
281 fetch_when_ready_callback_ = callback;
316 } 282 }
317 283
318 MarkEmptyCategoriesAsLoading(); 284 MarkEmptyCategoriesAsLoading();
319 285
320 NTPSnippetsFetcher::Params params = BuildFetchParams(); 286 NTPSnippetsFetcher::Params params = BuildFetchParams();
321 params.interactive_request = interactive_request; 287 params.interactive_request = interactive_request;
322 snippets_fetcher_->FetchSnippets( 288 snippets_fetcher_->FetchSnippets(
323 params, base::BindOnce(&RemoteSuggestionsProvider::OnFetchFinished, 289 params,
324 base::Unretained(this), interactive_request)); 290 base::BindOnce(&RemoteSuggestionsProvider::OnFetchFinished,
291 base::Unretained(this), callback, interactive_request));
325 } 292 }
326 293
327 void RemoteSuggestionsProvider::Fetch( 294 void RemoteSuggestionsProvider::Fetch(
328 const Category& category, 295 const Category& category,
329 const std::set<std::string>& known_suggestion_ids, 296 const std::set<std::string>& known_suggestion_ids,
330 const FetchDoneCallback& callback) { 297 const FetchDoneCallback& callback) {
331 if (!ready()) { 298 if (!ready()) {
332 CallWithEmptyResults(callback, 299 CallWithEmptyResults(callback,
333 Status(StatusCode::TEMPORARY_ERROR, 300 Status(StatusCode::TEMPORARY_ERROR,
334 "RemoteSuggestionsProvider is not ready!")); 301 "RemoteSuggestionsProvider is not ready!"));
(...skipping 30 matching lines...) Expand all
365 void RemoteSuggestionsProvider::MarkEmptyCategoriesAsLoading() { 332 void RemoteSuggestionsProvider::MarkEmptyCategoriesAsLoading() {
366 for (const auto& item : category_contents_) { 333 for (const auto& item : category_contents_) {
367 Category category = item.first; 334 Category category = item.first;
368 const CategoryContent& content = item.second; 335 const CategoryContent& content = item.second;
369 if (content.snippets.empty()) { 336 if (content.snippets.empty()) {
370 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE_LOADING); 337 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE_LOADING);
371 } 338 }
372 } 339 }
373 } 340 }
374 341
375 void RemoteSuggestionsProvider::RescheduleFetching(bool force) {
376 // The scheduler only exists on Android so far, it's null on other platforms.
377 if (!scheduler_) {
378 return;
379 }
380
381 if (ready()) {
382 base::TimeDelta old_interval_wifi = base::TimeDelta::FromInternalValue(
383 pref_service_->GetInt64(prefs::kSnippetBackgroundFetchingIntervalWifi));
384 base::TimeDelta old_interval_fallback =
385 base::TimeDelta::FromInternalValue(pref_service_->GetInt64(
386 prefs::kSnippetBackgroundFetchingIntervalFallback));
387 UserClassifier::UserClass user_class = user_classifier_->GetUserClass();
388 base::TimeDelta interval_wifi =
389 GetFetchingInterval(/*is_wifi=*/true, user_class);
390 base::TimeDelta interval_fallback =
391 GetFetchingInterval(/*is_wifi=*/false, user_class);
392 if (force || interval_wifi != old_interval_wifi ||
393 interval_fallback != old_interval_fallback) {
394 scheduler_->Schedule(interval_wifi, interval_fallback);
395 pref_service_->SetInt64(prefs::kSnippetBackgroundFetchingIntervalWifi,
396 interval_wifi.ToInternalValue());
397 pref_service_->SetInt64(prefs::kSnippetBackgroundFetchingIntervalFallback,
398 interval_fallback.ToInternalValue());
399 }
400 } else {
401 // If we're NOT_INITED, we don't know whether to schedule or unschedule.
402 // If |force| is false, all is well: We'll reschedule on the next state
403 // change anyway. If it's true, then unschedule here, to make sure that the
404 // next reschedule actually happens.
405 if (state_ != State::NOT_INITED || force) {
406 scheduler_->Unschedule();
407 pref_service_->ClearPref(prefs::kSnippetBackgroundFetchingIntervalWifi);
408 pref_service_->ClearPref(
409 prefs::kSnippetBackgroundFetchingIntervalFallback);
410 }
411 }
412 }
413
414 CategoryStatus RemoteSuggestionsProvider::GetCategoryStatus(Category category) { 342 CategoryStatus RemoteSuggestionsProvider::GetCategoryStatus(Category category) {
415 auto content_it = category_contents_.find(category); 343 auto content_it = category_contents_.find(category);
416 DCHECK(content_it != category_contents_.end()); 344 DCHECK(content_it != category_contents_.end());
417 return content_it->second.status; 345 return content_it->second.status;
418 } 346 }
419 347
420 CategoryInfo RemoteSuggestionsProvider::GetCategoryInfo(Category category) { 348 CategoryInfo RemoteSuggestionsProvider::GetCategoryInfo(Category category) {
421 auto content_it = category_contents_.find(category); 349 auto content_it = category_contents_.find(category);
422 DCHECK(content_it != category_contents_.end()); 350 DCHECK(content_it != category_contents_.end());
423 return content_it->second.info; 351 return content_it->second.info;
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
627 void RemoteSuggestionsProvider::OnDatabaseError() { 555 void RemoteSuggestionsProvider::OnDatabaseError() {
628 EnterState(State::ERROR_OCCURRED); 556 EnterState(State::ERROR_OCCURRED);
629 UpdateAllCategoryStatus(CategoryStatus::LOADING_ERROR); 557 UpdateAllCategoryStatus(CategoryStatus::LOADING_ERROR);
630 } 558 }
631 559
632 void RemoteSuggestionsProvider::OnFetchMoreFinished( 560 void RemoteSuggestionsProvider::OnFetchMoreFinished(
633 const FetchDoneCallback& fetching_callback, 561 const FetchDoneCallback& fetching_callback,
634 NTPSnippetsFetcher::FetchResult fetch_result, 562 NTPSnippetsFetcher::FetchResult fetch_result,
635 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories) { 563 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories) {
636 if (!fetched_categories) { 564 if (!fetched_categories) {
637 // TODO(fhorschig): Disambiguate the kind of error that led here. 565 // TODO(fhorschig): Disambiguate the kind of error that led here. Use a
566 // common function here and in OnFetchFinished().
638 CallWithEmptyResults(fetching_callback, 567 CallWithEmptyResults(fetching_callback,
639 Status(StatusCode::PERMANENT_ERROR, 568 Status(StatusCode::PERMANENT_ERROR,
640 "The NTPSnippetsFetcher did not " 569 "The NTPSnippetsFetcher did not "
641 "complete the fetching successfully.")); 570 "complete the fetching successfully."));
642 return; 571 return;
643 } 572 }
644 if (fetched_categories->size() != 1u) { 573 if (fetched_categories->size() != 1u) {
645 LOG(DFATAL) << "Requested one exclusive category but received " 574 LOG(DFATAL) << "Requested one exclusive category but received "
646 << fetched_categories->size() << " categories."; 575 << fetched_categories->size() << " categories.";
647 CallWithEmptyResults(fetching_callback, 576 CallWithEmptyResults(fetching_callback,
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
686 // once the snippets fetcher supports concurrent requests. We can then see if 615 // once the snippets fetcher supports concurrent requests. We can then see if
687 // Nuke should also cancel outstanding requests or we want to check the 616 // Nuke should also cancel outstanding requests or we want to check the
688 // status. 617 // status.
689 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE); 618 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE);
690 // Notify callers and observers. 619 // Notify callers and observers.
691 fetching_callback.Run(Status(StatusCode::SUCCESS), std::move(result)); 620 fetching_callback.Run(Status(StatusCode::SUCCESS), std::move(result));
692 NotifyNewSuggestions(category, *existing_content); 621 NotifyNewSuggestions(category, *existing_content);
693 } 622 }
694 623
695 void RemoteSuggestionsProvider::OnFetchFinished( 624 void RemoteSuggestionsProvider::OnFetchFinished(
625 const FetchStatusCallback& callback,
696 bool interactive_request, 626 bool interactive_request,
697 NTPSnippetsFetcher::FetchResult fetch_result, 627 NTPSnippetsFetcher::FetchResult fetch_result,
698 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories) { 628 NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories) {
699 if (!ready()) { 629 if (!ready()) {
700 // TODO(tschumann): What happens if this was a user-triggered, interactive 630 // TODO(tschumann): What happens if this was a user-triggered, interactive
701 // request? Is the UI waiting indefinitely now? 631 // request? Is the UI waiting indefinitely now?
702 return; 632 return;
703 } 633 }
704 634
705 // Record the fetch time of a successfull background fetch. 635 // Record the fetch time of a successfull background fetch.
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
761 auto content_it = category_contents_.find(articles_category_); 691 auto content_it = category_contents_.find(articles_category_);
762 DCHECK(content_it != category_contents_.end()); 692 DCHECK(content_it != category_contents_.end());
763 const CategoryContent& content = content_it->second; 693 const CategoryContent& content = content_it->second;
764 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles", 694 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles",
765 content.snippets.size()); 695 content.snippets.size());
766 if (content.snippets.empty() && !content.dismissed.empty()) { 696 if (content.snippets.empty() && !content.dismissed.empty()) {
767 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded", 697 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded",
768 content.dismissed.size()); 698 content.dismissed.size());
769 } 699 }
770 700
771 // Reschedule after a successful fetch. This resets all currently scheduled 701 if (fetch_result == NTPSnippetsFetcher::FetchResult::SUCCESS) {
772 // fetches, to make sure the fallback interval triggers only if no wifi fetch 702 callback.Run(Status(StatusCode::SUCCESS));
773 // succeeded, and also that we don't do a background fetch immediately after 703 } else {
774 // a user-initiated one. 704 // TODO(fhorschig): Disambiguate the kind of error that led here. Use a
775 if (fetched_categories) { 705 // common function here and in OnFetchMoreFinished().
776 RescheduleFetching(true); 706 callback.Run(Status(StatusCode::PERMANENT_ERROR,
707 "The NTPSnippetsFetcher did not "
708 "complete the fetching successfully."));
777 } 709 }
778 } 710 }
779 711
780 void RemoteSuggestionsProvider::ArchiveSnippets( 712 void RemoteSuggestionsProvider::ArchiveSnippets(
781 CategoryContent* content, 713 CategoryContent* content,
782 NTPSnippet::PtrVector* to_archive) { 714 NTPSnippet::PtrVector* to_archive) {
783 // Archive previous snippets - move them at the beginning of the list. 715 // Archive previous snippets - move them at the beginning of the list.
784 content->archived.insert(content->archived.begin(), 716 content->archived.insert(content->archived.begin(),
785 std::make_move_iterator(to_archive->begin()), 717 std::make_move_iterator(to_archive->begin()),
786 std::make_move_iterator(to_archive->end())); 718 std::make_move_iterator(to_archive->end()));
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
1008 940
1009 auto article_category_it = category_contents_.find(articles_category_); 941 auto article_category_it = category_contents_.find(articles_category_);
1010 DCHECK(article_category_it != category_contents_.end()); 942 DCHECK(article_category_it != category_contents_.end());
1011 if (article_category_it->second.snippets.empty() || fetch_when_ready_) { 943 if (article_category_it->second.snippets.empty() || fetch_when_ready_) {
1012 // TODO(jkrcal): Fetching snippets automatically upon creation of this 944 // TODO(jkrcal): Fetching snippets automatically upon creation of this
1013 // lazily created service can cause troubles, e.g. in unit tests where 945 // lazily created service can cause troubles, e.g. in unit tests where
1014 // network I/O is not allowed. 946 // network I/O is not allowed.
1015 // Either add a DCHECK here that we actually are allowed to do network I/O 947 // Either add a DCHECK here that we actually are allowed to do network I/O
1016 // or change the logic so that some explicit call is always needed for the 948 // or change the logic so that some explicit call is always needed for the
1017 // network request. 949 // network request.
1018 FetchSnippets(/*interactive_request=*/false); 950 FetchSnippets(fetch_when_ready_interactive_, fetch_when_ready_callback_);
1019 fetch_when_ready_ = false; 951 fetch_when_ready_ = false;
1020 } 952 }
1021 953
1022 for (const auto& item : category_contents_) { 954 for (const auto& item : category_contents_) {
1023 Category category = item.first; 955 Category category = item.first;
1024 const CategoryContent& content = item.second; 956 const CategoryContent& content = item.second;
1025 // FetchSnippets has set the status to |AVAILABLE_LOADING| if relevant, 957 // FetchSnippets has set the status to |AVAILABLE_LOADING| if relevant,
1026 // otherwise we transition to |AVAILABLE| here. 958 // otherwise we transition to |AVAILABLE| here.
1027 if (content.status != CategoryStatus::AVAILABLE_LOADING) { 959 if (content.status != CategoryStatus::AVAILABLE_LOADING) {
1028 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE); 960 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE);
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
1074 void RemoteSuggestionsProvider::OnStatusChanged( 1006 void RemoteSuggestionsProvider::OnStatusChanged(
1075 RemoteSuggestionsStatus old_status, 1007 RemoteSuggestionsStatus old_status,
1076 RemoteSuggestionsStatus new_status) { 1008 RemoteSuggestionsStatus new_status) {
1077 switch (new_status) { 1009 switch (new_status) {
1078 case RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN: 1010 case RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN:
1079 if (old_status == RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT) { 1011 if (old_status == RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT) {
1080 DCHECK(state_ == State::READY); 1012 DCHECK(state_ == State::READY);
1081 // Clear nonpersonalized suggestions. 1013 // Clear nonpersonalized suggestions.
1082 NukeAllSnippets(); 1014 NukeAllSnippets();
1083 // Fetch personalized ones. 1015 // Fetch personalized ones.
1084 FetchSnippets(/*interactive_request=*/true); 1016 // TODO(jkrcal): Loop in SchedulingRemoteSuggestionsProvider somehow.
1017 FetchSnippets(/*interactive_request=*/true, FetchStatusCallback());
1085 } else { 1018 } else {
1086 // Do not change the status. That will be done in EnterStateReady(). 1019 // Do not change the status. That will be done in EnterStateReady().
1087 EnterState(State::READY); 1020 EnterState(State::READY);
1088 } 1021 }
1089 break; 1022 break;
1090 1023
1091 case RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT: 1024 case RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT:
1092 if (old_status == RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN) { 1025 if (old_status == RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN) {
1093 DCHECK(state_ == State::READY); 1026 DCHECK(state_ == State::READY);
1094 // Clear personalized suggestions. 1027 // Clear personalized suggestions.
1095 NukeAllSnippets(); 1028 NukeAllSnippets();
1096 // Fetch nonpersonalized ones. 1029 // Fetch nonpersonalized ones.
1097 FetchSnippets(/*interactive_request=*/true); 1030 // TODO(jkrcal): Loop in SchedulingRemoteSuggestionsProvider somehow.
1031 FetchSnippets(/*interactive_request=*/true, FetchStatusCallback());
1098 } else { 1032 } else {
1099 // Do not change the status. That will be done in EnterStateReady(). 1033 // Do not change the status. That will be done in EnterStateReady().
1100 EnterState(State::READY); 1034 EnterState(State::READY);
1101 } 1035 }
1102 break; 1036 break;
1103 1037
1104 case RemoteSuggestionsStatus::EXPLICITLY_DISABLED: 1038 case RemoteSuggestionsStatus::EXPLICITLY_DISABLED:
1105 EnterState(State::DISABLED); 1039 EnterState(State::DISABLED);
1106 UpdateAllCategoryStatus(CategoryStatus::CATEGORY_EXPLICITLY_DISABLED); 1040 UpdateAllCategoryStatus(CategoryStatus::CATEGORY_EXPLICITLY_DISABLED);
1107 break; 1041 break;
(...skipping 19 matching lines...) Expand all
1127 // Initial state, it should not be possible to get back there. 1061 // Initial state, it should not be possible to get back there.
1128 NOTREACHED(); 1062 NOTREACHED();
1129 break; 1063 break;
1130 1064
1131 case State::READY: 1065 case State::READY:
1132 DCHECK(state_ == State::NOT_INITED || state_ == State::DISABLED); 1066 DCHECK(state_ == State::NOT_INITED || state_ == State::DISABLED);
1133 1067
1134 DVLOG(1) << "Entering state: READY"; 1068 DVLOG(1) << "Entering state: READY";
1135 state_ = State::READY; 1069 state_ = State::READY;
1136 EnterStateReady(); 1070 EnterStateReady();
1071 provider_active_callback_.Run(/*active=*/true);
1137 break; 1072 break;
1138 1073
1139 case State::DISABLED: 1074 case State::DISABLED:
1140 DCHECK(state_ == State::NOT_INITED || state_ == State::READY); 1075 DCHECK(state_ == State::NOT_INITED || state_ == State::READY);
1141 1076
1142 DVLOG(1) << "Entering state: DISABLED"; 1077 DVLOG(1) << "Entering state: DISABLED";
1143 state_ = State::DISABLED; 1078 state_ = State::DISABLED;
1144 EnterStateDisabled(); 1079 EnterStateDisabled();
1080 provider_active_callback_.Run(/*active=*/false);
1145 break; 1081 break;
1146 1082
1147 case State::ERROR_OCCURRED: 1083 case State::ERROR_OCCURRED:
1148 DVLOG(1) << "Entering state: ERROR_OCCURRED"; 1084 DVLOG(1) << "Entering state: ERROR_OCCURRED";
1149 state_ = State::ERROR_OCCURRED; 1085 state_ = State::ERROR_OCCURRED;
1150 EnterStateError(); 1086 EnterStateError();
1087 provider_active_callback_.Run(/*active=*/false);
1151 break; 1088 break;
1152 1089
1153 case State::COUNT: 1090 case State::COUNT:
1154 NOTREACHED(); 1091 NOTREACHED();
1155 break; 1092 break;
1156 } 1093 }
1157
1158 // Schedule or un-schedule background fetching after each state change.
1159 RescheduleFetching(false);
1160 } 1094 }
1161 1095
1162 void RemoteSuggestionsProvider::NotifyNewSuggestions( 1096 void RemoteSuggestionsProvider::NotifyNewSuggestions(
1163 Category category, 1097 Category category,
1164 const CategoryContent& content) { 1098 const CategoryContent& content) {
1165 DCHECK(IsCategoryStatusAvailable(content.status)); 1099 DCHECK(IsCategoryStatusAvailable(content.status));
1166 1100
1167 std::vector<ContentSuggestion> result = 1101 std::vector<ContentSuggestion> result =
1168 ConvertToContentSuggestions(category, content.snippets); 1102 ConvertToContentSuggestions(category, content.snippets);
1169 1103
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
1332 RemoteSuggestionsProvider::CategoryContent::CategoryContent(CategoryContent&&) = 1266 RemoteSuggestionsProvider::CategoryContent::CategoryContent(CategoryContent&&) =
1333 default; 1267 default;
1334 1268
1335 RemoteSuggestionsProvider::CategoryContent::~CategoryContent() = default; 1269 RemoteSuggestionsProvider::CategoryContent::~CategoryContent() = default;
1336 1270
1337 RemoteSuggestionsProvider::CategoryContent& 1271 RemoteSuggestionsProvider::CategoryContent&
1338 RemoteSuggestionsProvider::CategoryContent::operator=(CategoryContent&&) = 1272 RemoteSuggestionsProvider::CategoryContent::operator=(CategoryContent&&) =
1339 default; 1273 default;
1340 1274
1341 } // namespace ntp_snippets 1275 } // namespace ntp_snippets
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698