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 |