Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "components/ntp_snippets/remote/scheduling_remote_suggestions_provider. h" | |
| 6 | |
| 7 #include <string> | |
| 8 #include <utility> | |
| 9 | |
| 10 #include "components/ntp_snippets/features.h" | |
| 11 #include "components/ntp_snippets/pref_names.h" | |
| 12 #include "components/ntp_snippets/remote/persistent_scheduler.h" | |
| 13 #include "components/ntp_snippets/status.h" | |
| 14 #include "components/ntp_snippets/user_classifier.h" | |
| 15 #include "components/prefs/pref_registry_simple.h" | |
| 16 #include "components/prefs/pref_service.h" | |
| 17 #include "components/variations/variations_associated_data.h" | |
| 18 | |
| 19 namespace ntp_snippets { | |
| 20 | |
| 21 namespace { | |
| 22 | |
| 23 // Default values for fetching intervals, fallback and wifi. | |
| 24 const double kDefaultFetchingIntervalRareNtpUser[] = {48.0, 24.0}; | |
| 25 const double kDefaultFetchingIntervalActiveNtpUser[] = {24.0, 6.0}; | |
| 26 const double kDefaultFetchingIntervalActiveSuggestionsConsumer[] = {24.0, 6.0}; | |
| 27 | |
| 28 // Variation parameters than can the default fetching intervals. | |
| 29 const char* kFetchingIntervalParamNameRareNtpUser[] = { | |
| 30 "fetching_interval_hours-fallback-rare_ntp_user", | |
| 31 "fetching_interval_hours-wifi-rare_ntp_user"}; | |
| 32 const char* kFetchingIntervalParamNameActiveNtpUser[] = { | |
| 33 "fetching_interval_hours-fallback-active_ntp_user", | |
| 34 "fetching_interval_hours-wifi-active_ntp_user"}; | |
| 35 const char* kFetchingIntervalParamNameActiveSuggestionsConsumer[] = { | |
| 36 "fetching_interval_hours-fallback-active_suggestions_consumer", | |
| 37 "fetching_interval_hours-wifi-active_suggestions_consumer"}; | |
| 38 | |
| 39 base::TimeDelta GetCurrentUpdateInterval( | |
|
Marc Treib
2016/12/19 12:59:24
GetDesiredUpdateInterval
jkrcal
2016/12/20 16:39:47
Yep, thanks!
| |
| 40 bool is_wifi, | |
| 41 UserClassifier::UserClass user_class) { | |
| 42 double default_value_hours = 0.0; | |
| 43 | |
| 44 const int index = is_wifi ? 1 : 0; | |
| 45 const char* param_name = nullptr; | |
| 46 switch (user_class) { | |
| 47 case UserClassifier::UserClass::RARE_NTP_USER: | |
| 48 default_value_hours = kDefaultFetchingIntervalRareNtpUser[index]; | |
| 49 param_name = kFetchingIntervalParamNameRareNtpUser[index]; | |
| 50 break; | |
| 51 case UserClassifier::UserClass::ACTIVE_NTP_USER: | |
| 52 default_value_hours = kDefaultFetchingIntervalActiveNtpUser[index]; | |
| 53 param_name = kFetchingIntervalParamNameActiveNtpUser[index]; | |
| 54 break; | |
| 55 case UserClassifier::UserClass::ACTIVE_SUGGESTIONS_CONSUMER: | |
| 56 default_value_hours = | |
| 57 kDefaultFetchingIntervalActiveSuggestionsConsumer[index]; | |
| 58 param_name = kFetchingIntervalParamNameActiveSuggestionsConsumer[index]; | |
| 59 break; | |
| 60 } | |
| 61 | |
| 62 double value_hours = variations::GetVariationParamByFeatureAsDouble( | |
| 63 ntp_snippets::kArticleSuggestionsFeature, param_name, | |
| 64 default_value_hours); | |
| 65 | |
| 66 return base::TimeDelta::FromSecondsD(value_hours * 3600.0); | |
| 67 } | |
| 68 | |
| 69 } // namespace | |
| 70 | |
| 71 struct SchedulingRemoteSuggestionsProvider::FetchingSchedule { | |
| 72 base::TimeDelta interval_wifi; | |
| 73 base::TimeDelta interval_fallback; | |
| 74 | |
| 75 static FetchingSchedule Empty() { | |
| 76 return FetchingSchedule{base::TimeDelta::FromHours(0), | |
| 77 base::TimeDelta::FromHours(0)}; | |
|
Marc Treib
2016/12/19 12:59:23
Just use the default ctor of TimeDelta.
(In fact,
jkrcal
2016/12/20 16:39:47
Done.
| |
| 78 } | |
| 79 | |
| 80 bool operator!=(const FetchingSchedule& other) const { | |
|
Marc Treib
2016/12/19 12:59:23
nit: If it has !=, it should probably also have ==
jkrcal
2016/12/20 16:39:47
Done.
| |
| 81 return interval_wifi != other.interval_wifi || | |
| 82 interval_fallback != other.interval_fallback; | |
| 83 } | |
| 84 | |
| 85 bool is_empty() const { | |
| 86 return interval_wifi.is_zero() && interval_fallback.is_zero(); | |
| 87 } | |
| 88 }; | |
| 89 | |
| 90 SchedulingRemoteSuggestionsProvider::SchedulingRemoteSuggestionsProvider( | |
| 91 Observer* observer, | |
| 92 CategoryFactory* category_factory, | |
| 93 std::unique_ptr<RemoteSuggestionsProvider> provider, | |
| 94 PersistentScheduler* persistent_scheduler, | |
| 95 const UserClassifier* user_classifier, | |
| 96 PrefService* pref_service) | |
| 97 : ContentSuggestionsProvider(observer, category_factory), | |
| 98 provider_(std::move(provider)), | |
| 99 persistent_scheduler_(persistent_scheduler), | |
| 100 user_classifier_(user_classifier), | |
| 101 pref_service_(pref_service) { | |
| 102 DCHECK(user_classifier) << "non-null UserClassifier must be provided"; | |
| 103 DCHECK(pref_service) << "non-null pref service is needed"; | |
|
Marc Treib
2016/12/19 12:59:23
nit: Comments aren't really necessary; they're obv
jkrcal
2016/12/20 16:39:47
Done.
| |
| 104 | |
| 105 provider->SetProviderStatusCallback(base::BindRepeating( | |
| 106 &SchedulingRemoteSuggestionsProvider::OnProviderStatusChanged, | |
| 107 base::Unretained(this))); | |
| 108 } | |
| 109 | |
| 110 SchedulingRemoteSuggestionsProvider::~SchedulingRemoteSuggestionsProvider() = | |
| 111 default; | |
| 112 | |
| 113 // static | |
| 114 void SchedulingRemoteSuggestionsProvider::RegisterProfilePrefs( | |
| 115 PrefRegistrySimple* registry) { | |
| 116 registry->RegisterInt64Pref(prefs::kSnippetBackgroundFetchingIntervalWifi, 0); | |
| 117 registry->RegisterInt64Pref(prefs::kSnippetBackgroundFetchingIntervalFallback, | |
| 118 0); | |
| 119 } | |
| 120 | |
| 121 void SchedulingRemoteSuggestionsProvider::RescheduleFetching() { | |
| 122 // Force the reschedule by stopping and starting it again. | |
| 123 StopScheduling(); | |
| 124 StartScheduling(); | |
| 125 } | |
| 126 | |
| 127 void SchedulingRemoteSuggestionsProvider::OnFetchDue() { | |
| 128 provider_->RefetchInTheBackground( | |
| 129 base::Bind(&SchedulingRemoteSuggestionsProvider::OnFetchCompleted, | |
| 130 base::Unretained(this))); | |
| 131 } | |
| 132 | |
| 133 | |
| 134 CategoryStatus SchedulingRemoteSuggestionsProvider::GetCategoryStatus( | |
| 135 Category category) { | |
| 136 return provider_->GetCategoryStatus(category); | |
| 137 } | |
| 138 | |
| 139 CategoryInfo SchedulingRemoteSuggestionsProvider::GetCategoryInfo( | |
| 140 Category category) { | |
| 141 return provider_->GetCategoryInfo(category); | |
| 142 } | |
| 143 | |
| 144 void SchedulingRemoteSuggestionsProvider::DismissSuggestion( | |
| 145 const ContentSuggestion::ID& suggestion_id) { | |
| 146 provider_->DismissSuggestion(suggestion_id); | |
| 147 } | |
| 148 | |
| 149 void SchedulingRemoteSuggestionsProvider::FetchSuggestionImage( | |
| 150 const ContentSuggestion::ID& suggestion_id, | |
| 151 const ImageFetchedCallback& callback) { | |
| 152 provider_->FetchSuggestionImage(suggestion_id, callback); | |
| 153 } | |
| 154 | |
| 155 void SchedulingRemoteSuggestionsProvider::Fetch( | |
| 156 const Category& category, | |
| 157 const std::set<std::string>& known_suggestion_ids, | |
| 158 const FetchDoneCallback& callback) { | |
| 159 provider_->Fetch( | |
| 160 category, known_suggestion_ids, | |
| 161 base::Bind(&SchedulingRemoteSuggestionsProvider::FetchFinished, | |
| 162 base::Unretained(this), callback)); | |
| 163 } | |
| 164 | |
| 165 void SchedulingRemoteSuggestionsProvider::ReloadSuggestions() { | |
| 166 provider_->ReloadSuggestions(); | |
| 167 } | |
| 168 | |
| 169 void SchedulingRemoteSuggestionsProvider::ClearHistory( | |
| 170 base::Time begin, | |
| 171 base::Time end, | |
| 172 const base::Callback<bool(const GURL& url)>& filter) { | |
| 173 provider_->ClearHistory(begin, end, filter); | |
| 174 } | |
| 175 | |
| 176 void SchedulingRemoteSuggestionsProvider::ClearCachedSuggestions( | |
| 177 Category category) { | |
| 178 provider_->ClearCachedSuggestions(category); | |
| 179 } | |
| 180 | |
| 181 void SchedulingRemoteSuggestionsProvider::OnSignInStateChanged() { | |
| 182 provider_->OnSignInStateChanged(); | |
| 183 } | |
| 184 | |
| 185 void SchedulingRemoteSuggestionsProvider::GetDismissedSuggestionsForDebugging( | |
| 186 Category category, | |
| 187 const DismissedSuggestionsCallback& callback) { | |
| 188 provider_->GetDismissedSuggestionsForDebugging(category, callback); | |
| 189 } | |
| 190 | |
| 191 void SchedulingRemoteSuggestionsProvider::ClearDismissedSuggestionsForDebugging( | |
| 192 Category category) { | |
| 193 provider_->ClearDismissedSuggestionsForDebugging(category); | |
| 194 } | |
| 195 | |
| 196 void SchedulingRemoteSuggestionsProvider::OnProviderStatusChanged( | |
| 197 RemoteSuggestionsProvider::ProviderStatus status) { | |
| 198 switch (status) { | |
| 199 case RemoteSuggestionsProvider::ProviderStatus::ACTIVE: | |
| 200 StartScheduling(); | |
| 201 return; | |
| 202 case RemoteSuggestionsProvider::ProviderStatus::INACTIVE: | |
| 203 StopScheduling(); | |
| 204 return; | |
| 205 } | |
|
Marc Treib
2016/12/19 12:59:23
NOTREACHED();
jkrcal
2016/12/20 16:39:47
Done. Is this really needed? Does not the compiler
| |
| 206 } | |
| 207 | |
| 208 void SchedulingRemoteSuggestionsProvider::StartScheduling() { | |
| 209 // The scheduler only exists on Android so far, it's null on other platforms. | |
| 210 if (!persistent_scheduler_) { | |
| 211 return; | |
| 212 } | |
| 213 | |
| 214 FetchingSchedule last_schedule = GetLastFetchingSchedule(); | |
| 215 FetchingSchedule schedule = GetDesiredFetchingSchedule(); | |
| 216 | |
| 217 // Reset the schedule only if the parameters have changed. | |
| 218 if (last_schedule != schedule) { | |
| 219 ApplyFetchingSchedule(schedule); | |
| 220 } | |
| 221 } | |
| 222 | |
| 223 void SchedulingRemoteSuggestionsProvider::StopScheduling() { | |
| 224 // The scheduler only exists on Android so far, it's null on other platforms. | |
| 225 if (!persistent_scheduler_) { | |
| 226 return; | |
| 227 } | |
| 228 | |
| 229 // Do not unschedule if already switched off | |
| 230 FetchingSchedule last_schedule = GetLastFetchingSchedule(); | |
| 231 if (last_schedule.is_empty()) { | |
| 232 return; | |
| 233 } | |
| 234 | |
| 235 persistent_scheduler_->Unschedule(); | |
| 236 | |
| 237 StoreLastFetchingSchedule(FetchingSchedule::Empty()); | |
| 238 } | |
| 239 | |
| 240 void SchedulingRemoteSuggestionsProvider::ApplyFetchingSchedule( | |
| 241 const FetchingSchedule& schedule) { | |
| 242 persistent_scheduler_->Schedule(schedule.interval_wifi, | |
| 243 schedule.interval_fallback); | |
| 244 | |
| 245 StoreLastFetchingSchedule(schedule); | |
| 246 } | |
| 247 | |
| 248 SchedulingRemoteSuggestionsProvider::FetchingSchedule | |
| 249 SchedulingRemoteSuggestionsProvider::GetDesiredFetchingSchedule() { | |
| 250 UserClassifier::UserClass user_class = user_classifier_->GetUserClass(); | |
| 251 | |
| 252 FetchingSchedule schedule; | |
| 253 schedule.interval_wifi = | |
| 254 GetCurrentUpdateInterval(/*is_wifi=*/true, user_class); | |
| 255 schedule.interval_fallback = | |
| 256 GetCurrentUpdateInterval(/*is_wifi=*/false, user_class); | |
| 257 return schedule; | |
| 258 } | |
| 259 | |
| 260 SchedulingRemoteSuggestionsProvider::FetchingSchedule | |
| 261 SchedulingRemoteSuggestionsProvider::GetLastFetchingSchedule() const { | |
| 262 FetchingSchedule schedule; | |
| 263 schedule.interval_wifi = base::TimeDelta::FromInternalValue( | |
| 264 pref_service_->GetInt64(prefs::kSnippetBackgroundFetchingIntervalWifi)); | |
| 265 schedule.interval_fallback = | |
| 266 base::TimeDelta::FromInternalValue(pref_service_->GetInt64( | |
| 267 prefs::kSnippetBackgroundFetchingIntervalFallback)); | |
| 268 return schedule; | |
| 269 } | |
| 270 | |
| 271 void SchedulingRemoteSuggestionsProvider::StoreLastFetchingSchedule( | |
| 272 const FetchingSchedule& schedule) { | |
| 273 pref_service_->SetInt64( | |
| 274 prefs::kSnippetBackgroundFetchingIntervalWifi, | |
| 275 schedule.interval_wifi.ToInternalValue()); | |
| 276 pref_service_->SetInt64( | |
| 277 prefs::kSnippetBackgroundFetchingIntervalFallback, | |
| 278 schedule.interval_fallback.ToInternalValue()); | |
| 279 } | |
| 280 | |
| 281 void SchedulingRemoteSuggestionsProvider::FetchFinished( | |
| 282 const FetchDoneCallback& callback, | |
| 283 Status status_code, | |
| 284 std::vector<ContentSuggestion> suggestions) { | |
| 285 OnFetchCompleted(status_code); | |
| 286 callback.Run(status_code, std::move(suggestions)); | |
| 287 } | |
| 288 | |
| 289 void SchedulingRemoteSuggestionsProvider::OnFetchCompleted( | |
| 290 Status fetch_status) { | |
| 291 // The scheduler only exists on Android so far, it's null on other platforms. | |
| 292 if (!persistent_scheduler_) { | |
| 293 return; | |
| 294 } | |
| 295 | |
| 296 if (fetch_status.code != StatusCode::SUCCESS) { | |
| 297 return; | |
| 298 } | |
| 299 | |
| 300 // Reschedule after a successful fetch. This resets all currently scheduled | |
| 301 // fetches, to make sure the fallback interval triggers only if no wifi fetch | |
| 302 // succeeded, and also that we don't do a background fetch immediately after | |
| 303 // a user-initiated one. | |
| 304 ApplyFetchingSchedule(GetLastFetchingSchedule()); | |
|
Marc Treib
2016/12/19 12:59:23
Just call RescheduleFetching?
jkrcal
2016/12/20 16:39:47
I prefer it this way because RescheduleFetching()
| |
| 305 } | |
| 306 | |
| 307 } // namespace ntp_snippets | |
| OLD | NEW |