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