| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/ntp_snippets/remote/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 Loading... |
| 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, ¶m_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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |