| 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 GetDesiredUpdateInterval( |
| 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(), |
| 77 base::TimeDelta()}; |
| 78 } |
| 79 |
| 80 bool operator==(const FetchingSchedule& other) const { |
| 81 return interval_wifi == other.interval_wifi && |
| 82 interval_fallback == other.interval_fallback; |
| 83 } |
| 84 |
| 85 bool operator!=(const FetchingSchedule& other) const { |
| 86 return !operator==(other); |
| 87 } |
| 88 |
| 89 bool is_empty() const { |
| 90 return interval_wifi.is_zero() && interval_fallback.is_zero(); |
| 91 } |
| 92 }; |
| 93 |
| 94 SchedulingRemoteSuggestionsProvider::SchedulingRemoteSuggestionsProvider( |
| 95 Observer* observer, |
| 96 std::unique_ptr<RemoteSuggestionsProvider> provider, |
| 97 PersistentScheduler* persistent_scheduler, |
| 98 const UserClassifier* user_classifier, |
| 99 PrefService* pref_service) |
| 100 : ContentSuggestionsProvider(observer), |
| 101 RemoteSuggestionsScheduler(), |
| 102 provider_(std::move(provider)), |
| 103 persistent_scheduler_(persistent_scheduler), |
| 104 user_classifier_(user_classifier), |
| 105 pref_service_(pref_service) { |
| 106 DCHECK(user_classifier); |
| 107 DCHECK(pref_service); |
| 108 |
| 109 provider_->SetProviderStatusCallback( |
| 110 base::MakeUnique<RemoteSuggestionsProvider::ProviderStatusCallback>( |
| 111 base::BindRepeating( |
| 112 &SchedulingRemoteSuggestionsProvider::OnProviderStatusChanged, |
| 113 base::Unretained(this)))); |
| 114 } |
| 115 |
| 116 SchedulingRemoteSuggestionsProvider::~SchedulingRemoteSuggestionsProvider() = |
| 117 default; |
| 118 |
| 119 // static |
| 120 void SchedulingRemoteSuggestionsProvider::RegisterProfilePrefs( |
| 121 PrefRegistrySimple* registry) { |
| 122 registry->RegisterInt64Pref(prefs::kSnippetBackgroundFetchingIntervalWifi, 0); |
| 123 registry->RegisterInt64Pref(prefs::kSnippetBackgroundFetchingIntervalFallback, |
| 124 0); |
| 125 } |
| 126 |
| 127 void SchedulingRemoteSuggestionsProvider::RescheduleFetching() { |
| 128 // Force the reschedule by stopping and starting it again. |
| 129 StopScheduling(); |
| 130 StartScheduling(); |
| 131 } |
| 132 |
| 133 void SchedulingRemoteSuggestionsProvider::OnPersistentSchedulerWakeUp() { |
| 134 provider_->RefetchInTheBackground( |
| 135 base::MakeUnique<RemoteSuggestionsProvider::FetchStatusCallback>( |
| 136 base::Bind(&SchedulingRemoteSuggestionsProvider::OnFetchCompleted, |
| 137 base::Unretained(this)))); |
| 138 } |
| 139 |
| 140 |
| 141 CategoryStatus SchedulingRemoteSuggestionsProvider::GetCategoryStatus( |
| 142 Category category) { |
| 143 return provider_->GetCategoryStatus(category); |
| 144 } |
| 145 |
| 146 CategoryInfo SchedulingRemoteSuggestionsProvider::GetCategoryInfo( |
| 147 Category category) { |
| 148 return provider_->GetCategoryInfo(category); |
| 149 } |
| 150 |
| 151 void SchedulingRemoteSuggestionsProvider::DismissSuggestion( |
| 152 const ContentSuggestion::ID& suggestion_id) { |
| 153 provider_->DismissSuggestion(suggestion_id); |
| 154 } |
| 155 |
| 156 void SchedulingRemoteSuggestionsProvider::FetchSuggestionImage( |
| 157 const ContentSuggestion::ID& suggestion_id, |
| 158 const ImageFetchedCallback& callback) { |
| 159 provider_->FetchSuggestionImage(suggestion_id, callback); |
| 160 } |
| 161 |
| 162 void SchedulingRemoteSuggestionsProvider::Fetch( |
| 163 const Category& category, |
| 164 const std::set<std::string>& known_suggestion_ids, |
| 165 const FetchDoneCallback& callback) { |
| 166 provider_->Fetch( |
| 167 category, known_suggestion_ids, |
| 168 base::Bind(&SchedulingRemoteSuggestionsProvider::FetchFinished, |
| 169 base::Unretained(this), callback)); |
| 170 } |
| 171 |
| 172 void SchedulingRemoteSuggestionsProvider::ReloadSuggestions() { |
| 173 provider_->ReloadSuggestions(); |
| 174 } |
| 175 |
| 176 void SchedulingRemoteSuggestionsProvider::ClearHistory( |
| 177 base::Time begin, |
| 178 base::Time end, |
| 179 const base::Callback<bool(const GURL& url)>& filter) { |
| 180 provider_->ClearHistory(begin, end, filter); |
| 181 } |
| 182 |
| 183 void SchedulingRemoteSuggestionsProvider::ClearCachedSuggestions( |
| 184 Category category) { |
| 185 provider_->ClearCachedSuggestions(category); |
| 186 } |
| 187 |
| 188 void SchedulingRemoteSuggestionsProvider::OnSignInStateChanged() { |
| 189 provider_->OnSignInStateChanged(); |
| 190 } |
| 191 |
| 192 void SchedulingRemoteSuggestionsProvider::GetDismissedSuggestionsForDebugging( |
| 193 Category category, |
| 194 const DismissedSuggestionsCallback& callback) { |
| 195 provider_->GetDismissedSuggestionsForDebugging(category, callback); |
| 196 } |
| 197 |
| 198 void SchedulingRemoteSuggestionsProvider::ClearDismissedSuggestionsForDebugging( |
| 199 Category category) { |
| 200 provider_->ClearDismissedSuggestionsForDebugging(category); |
| 201 } |
| 202 |
| 203 void SchedulingRemoteSuggestionsProvider::OnProviderStatusChanged( |
| 204 RemoteSuggestionsProvider::ProviderStatus status) { |
| 205 switch (status) { |
| 206 case RemoteSuggestionsProvider::ProviderStatus::ACTIVE: |
| 207 StartScheduling(); |
| 208 return; |
| 209 case RemoteSuggestionsProvider::ProviderStatus::INACTIVE: |
| 210 StopScheduling(); |
| 211 return; |
| 212 } |
| 213 NOTREACHED(); |
| 214 } |
| 215 |
| 216 void SchedulingRemoteSuggestionsProvider::StartScheduling() { |
| 217 // The scheduler only exists on Android so far, it's null on other platforms. |
| 218 if (!persistent_scheduler_) { |
| 219 return; |
| 220 } |
| 221 |
| 222 FetchingSchedule last_schedule = GetLastFetchingSchedule(); |
| 223 FetchingSchedule schedule = GetDesiredFetchingSchedule(); |
| 224 |
| 225 // Reset the schedule only if the parameters have changed. |
| 226 if (last_schedule != schedule) { |
| 227 ApplyFetchingSchedule(schedule); |
| 228 } |
| 229 } |
| 230 |
| 231 void SchedulingRemoteSuggestionsProvider::StopScheduling() { |
| 232 // The scheduler only exists on Android so far, it's null on other platforms. |
| 233 if (!persistent_scheduler_) { |
| 234 return; |
| 235 } |
| 236 |
| 237 // Do not unschedule if already switched off |
| 238 FetchingSchedule last_schedule = GetLastFetchingSchedule(); |
| 239 if (last_schedule.is_empty()) { |
| 240 return; |
| 241 } |
| 242 |
| 243 persistent_scheduler_->Unschedule(); |
| 244 |
| 245 StoreLastFetchingSchedule(FetchingSchedule::Empty()); |
| 246 } |
| 247 |
| 248 void SchedulingRemoteSuggestionsProvider::ApplyFetchingSchedule( |
| 249 const FetchingSchedule& schedule) { |
| 250 persistent_scheduler_->Schedule(schedule.interval_wifi, |
| 251 schedule.interval_fallback); |
| 252 |
| 253 StoreLastFetchingSchedule(schedule); |
| 254 } |
| 255 |
| 256 SchedulingRemoteSuggestionsProvider::FetchingSchedule |
| 257 SchedulingRemoteSuggestionsProvider::GetDesiredFetchingSchedule() const { |
| 258 UserClassifier::UserClass user_class = user_classifier_->GetUserClass(); |
| 259 |
| 260 FetchingSchedule schedule; |
| 261 schedule.interval_wifi = |
| 262 GetDesiredUpdateInterval(/*is_wifi=*/true, user_class); |
| 263 schedule.interval_fallback = |
| 264 GetDesiredUpdateInterval(/*is_wifi=*/false, user_class); |
| 265 return schedule; |
| 266 } |
| 267 |
| 268 SchedulingRemoteSuggestionsProvider::FetchingSchedule |
| 269 SchedulingRemoteSuggestionsProvider::GetLastFetchingSchedule() const { |
| 270 FetchingSchedule schedule; |
| 271 schedule.interval_wifi = base::TimeDelta::FromInternalValue( |
| 272 pref_service_->GetInt64(prefs::kSnippetBackgroundFetchingIntervalWifi)); |
| 273 schedule.interval_fallback = |
| 274 base::TimeDelta::FromInternalValue(pref_service_->GetInt64( |
| 275 prefs::kSnippetBackgroundFetchingIntervalFallback)); |
| 276 return schedule; |
| 277 } |
| 278 |
| 279 void SchedulingRemoteSuggestionsProvider::StoreLastFetchingSchedule( |
| 280 const FetchingSchedule& schedule) { |
| 281 pref_service_->SetInt64( |
| 282 prefs::kSnippetBackgroundFetchingIntervalWifi, |
| 283 schedule.interval_wifi.ToInternalValue()); |
| 284 pref_service_->SetInt64( |
| 285 prefs::kSnippetBackgroundFetchingIntervalFallback, |
| 286 schedule.interval_fallback.ToInternalValue()); |
| 287 } |
| 288 |
| 289 void SchedulingRemoteSuggestionsProvider::FetchFinished( |
| 290 const FetchDoneCallback& callback, |
| 291 Status status_code, |
| 292 std::vector<ContentSuggestion> suggestions) { |
| 293 OnFetchCompleted(status_code); |
| 294 callback.Run(status_code, std::move(suggestions)); |
| 295 } |
| 296 |
| 297 void SchedulingRemoteSuggestionsProvider::OnFetchCompleted( |
| 298 Status fetch_status) { |
| 299 // The scheduler only exists on Android so far, it's null on other platforms. |
| 300 if (!persistent_scheduler_) { |
| 301 return; |
| 302 } |
| 303 |
| 304 if (fetch_status.code != StatusCode::SUCCESS) { |
| 305 return; |
| 306 } |
| 307 |
| 308 // Reschedule after a successful fetch. This resets all currently scheduled |
| 309 // fetches, to make sure the fallback interval triggers only if no wifi fetch |
| 310 // succeeded, and also that we don't do a background fetch immediately after |
| 311 // a user-initiated one. |
| 312 ApplyFetchingSchedule(GetLastFetchingSchedule()); |
| 313 } |
| 314 |
| 315 } // namespace ntp_snippets |
| OLD | NEW |