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 : RemoteSuggestionsProvider(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 void SchedulingRemoteSuggestionsProvider::SetProviderStatusCallback( |
| 141 std::unique_ptr<ProviderStatusCallback> callback) { |
| 142 provider_->SetProviderStatusCallback(std::move(callback)); |
| 143 } |
| 144 |
| 145 void SchedulingRemoteSuggestionsProvider::RefetchInTheBackground( |
| 146 std::unique_ptr<FetchStatusCallback> callback) { |
| 147 provider_->RefetchInTheBackground(std::move(callback)); |
| 148 } |
| 149 |
| 150 const NTPSnippetsFetcher* SchedulingRemoteSuggestionsProvider:: |
| 151 snippets_fetcher_for_testing_and_debugging() const { |
| 152 return provider_->snippets_fetcher_for_testing_and_debugging(); |
| 153 } |
| 154 |
| 155 CategoryStatus SchedulingRemoteSuggestionsProvider::GetCategoryStatus( |
| 156 Category category) { |
| 157 return provider_->GetCategoryStatus(category); |
| 158 } |
| 159 |
| 160 CategoryInfo SchedulingRemoteSuggestionsProvider::GetCategoryInfo( |
| 161 Category category) { |
| 162 return provider_->GetCategoryInfo(category); |
| 163 } |
| 164 |
| 165 void SchedulingRemoteSuggestionsProvider::DismissSuggestion( |
| 166 const ContentSuggestion::ID& suggestion_id) { |
| 167 provider_->DismissSuggestion(suggestion_id); |
| 168 } |
| 169 |
| 170 void SchedulingRemoteSuggestionsProvider::FetchSuggestionImage( |
| 171 const ContentSuggestion::ID& suggestion_id, |
| 172 const ImageFetchedCallback& callback) { |
| 173 provider_->FetchSuggestionImage(suggestion_id, callback); |
| 174 } |
| 175 |
| 176 void SchedulingRemoteSuggestionsProvider::Fetch( |
| 177 const Category& category, |
| 178 const std::set<std::string>& known_suggestion_ids, |
| 179 const FetchDoneCallback& callback) { |
| 180 provider_->Fetch( |
| 181 category, known_suggestion_ids, |
| 182 base::Bind(&SchedulingRemoteSuggestionsProvider::FetchFinished, |
| 183 base::Unretained(this), callback)); |
| 184 } |
| 185 |
| 186 void SchedulingRemoteSuggestionsProvider::ReloadSuggestions() { |
| 187 provider_->ReloadSuggestions(); |
| 188 } |
| 189 |
| 190 void SchedulingRemoteSuggestionsProvider::ClearHistory( |
| 191 base::Time begin, |
| 192 base::Time end, |
| 193 const base::Callback<bool(const GURL& url)>& filter) { |
| 194 provider_->ClearHistory(begin, end, filter); |
| 195 } |
| 196 |
| 197 void SchedulingRemoteSuggestionsProvider::ClearCachedSuggestions( |
| 198 Category category) { |
| 199 provider_->ClearCachedSuggestions(category); |
| 200 } |
| 201 |
| 202 void SchedulingRemoteSuggestionsProvider::OnSignInStateChanged() { |
| 203 provider_->OnSignInStateChanged(); |
| 204 } |
| 205 |
| 206 void SchedulingRemoteSuggestionsProvider::GetDismissedSuggestionsForDebugging( |
| 207 Category category, |
| 208 const DismissedSuggestionsCallback& callback) { |
| 209 provider_->GetDismissedSuggestionsForDebugging(category, callback); |
| 210 } |
| 211 |
| 212 void SchedulingRemoteSuggestionsProvider::ClearDismissedSuggestionsForDebugging( |
| 213 Category category) { |
| 214 provider_->ClearDismissedSuggestionsForDebugging(category); |
| 215 } |
| 216 |
| 217 void SchedulingRemoteSuggestionsProvider::OnProviderStatusChanged( |
| 218 RemoteSuggestionsProvider::ProviderStatus status) { |
| 219 switch (status) { |
| 220 case RemoteSuggestionsProvider::ProviderStatus::ACTIVE: |
| 221 StartScheduling(); |
| 222 return; |
| 223 case RemoteSuggestionsProvider::ProviderStatus::INACTIVE: |
| 224 StopScheduling(); |
| 225 return; |
| 226 } |
| 227 NOTREACHED(); |
| 228 } |
| 229 |
| 230 void SchedulingRemoteSuggestionsProvider::StartScheduling() { |
| 231 // The scheduler only exists on Android so far, it's null on other platforms. |
| 232 if (!persistent_scheduler_) { |
| 233 return; |
| 234 } |
| 235 |
| 236 FetchingSchedule last_schedule = GetLastFetchingSchedule(); |
| 237 FetchingSchedule schedule = GetDesiredFetchingSchedule(); |
| 238 |
| 239 // Reset the schedule only if the parameters have changed. |
| 240 if (last_schedule != schedule) { |
| 241 ApplyFetchingSchedule(schedule); |
| 242 } |
| 243 } |
| 244 |
| 245 void SchedulingRemoteSuggestionsProvider::StopScheduling() { |
| 246 // The scheduler only exists on Android so far, it's null on other platforms. |
| 247 if (!persistent_scheduler_) { |
| 248 return; |
| 249 } |
| 250 |
| 251 // Do not unschedule if already switched off |
| 252 FetchingSchedule last_schedule = GetLastFetchingSchedule(); |
| 253 if (last_schedule.is_empty()) { |
| 254 return; |
| 255 } |
| 256 |
| 257 persistent_scheduler_->Unschedule(); |
| 258 |
| 259 StoreLastFetchingSchedule(FetchingSchedule::Empty()); |
| 260 } |
| 261 |
| 262 void SchedulingRemoteSuggestionsProvider::ApplyFetchingSchedule( |
| 263 const FetchingSchedule& schedule) { |
| 264 persistent_scheduler_->Schedule(schedule.interval_wifi, |
| 265 schedule.interval_fallback); |
| 266 |
| 267 StoreLastFetchingSchedule(schedule); |
| 268 } |
| 269 |
| 270 SchedulingRemoteSuggestionsProvider::FetchingSchedule |
| 271 SchedulingRemoteSuggestionsProvider::GetDesiredFetchingSchedule() const { |
| 272 UserClassifier::UserClass user_class = user_classifier_->GetUserClass(); |
| 273 |
| 274 FetchingSchedule schedule; |
| 275 schedule.interval_wifi = |
| 276 GetDesiredUpdateInterval(/*is_wifi=*/true, user_class); |
| 277 schedule.interval_fallback = |
| 278 GetDesiredUpdateInterval(/*is_wifi=*/false, user_class); |
| 279 return schedule; |
| 280 } |
| 281 |
| 282 SchedulingRemoteSuggestionsProvider::FetchingSchedule |
| 283 SchedulingRemoteSuggestionsProvider::GetLastFetchingSchedule() const { |
| 284 FetchingSchedule schedule; |
| 285 schedule.interval_wifi = base::TimeDelta::FromInternalValue( |
| 286 pref_service_->GetInt64(prefs::kSnippetBackgroundFetchingIntervalWifi)); |
| 287 schedule.interval_fallback = |
| 288 base::TimeDelta::FromInternalValue(pref_service_->GetInt64( |
| 289 prefs::kSnippetBackgroundFetchingIntervalFallback)); |
| 290 return schedule; |
| 291 } |
| 292 |
| 293 void SchedulingRemoteSuggestionsProvider::StoreLastFetchingSchedule( |
| 294 const FetchingSchedule& schedule) { |
| 295 pref_service_->SetInt64( |
| 296 prefs::kSnippetBackgroundFetchingIntervalWifi, |
| 297 schedule.interval_wifi.ToInternalValue()); |
| 298 pref_service_->SetInt64( |
| 299 prefs::kSnippetBackgroundFetchingIntervalFallback, |
| 300 schedule.interval_fallback.ToInternalValue()); |
| 301 } |
| 302 |
| 303 void SchedulingRemoteSuggestionsProvider::FetchFinished( |
| 304 const FetchDoneCallback& callback, |
| 305 Status status_code, |
| 306 std::vector<ContentSuggestion> suggestions) { |
| 307 OnFetchCompleted(status_code); |
| 308 callback.Run(status_code, std::move(suggestions)); |
| 309 } |
| 310 |
| 311 void SchedulingRemoteSuggestionsProvider::OnFetchCompleted( |
| 312 Status fetch_status) { |
| 313 // The scheduler only exists on Android so far, it's null on other platforms. |
| 314 if (!persistent_scheduler_) { |
| 315 return; |
| 316 } |
| 317 |
| 318 if (fetch_status.code != StatusCode::SUCCESS) { |
| 319 return; |
| 320 } |
| 321 |
| 322 // Reschedule after a successful fetch. This resets all currently scheduled |
| 323 // fetches, to make sure the fallback interval triggers only if no wifi fetch |
| 324 // succeeded, and also that we don't do a background fetch immediately after |
| 325 // a user-initiated one. |
| 326 ApplyFetchingSchedule(GetLastFetchingSchedule()); |
| 327 } |
| 328 |
| 329 } // namespace ntp_snippets |
OLD | NEW |