forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontent_suggestions_service.h
426 lines (347 loc) · 18.6 KB
/
content_suggestions_service.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTIONS_SERVICE_H_
#define COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTIONS_SERVICE_H_
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "base/callback_forward.h"
#include "base/observer_list.h"
#include "base/optional.h"
#include "base/scoped_observer.h"
#include "base/task/cancelable_task_tracker.h"
#include "base/time/time.h"
#include "components/history/core/browser/history_service.h"
#include "components/history/core/browser/history_service_observer.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h"
#include "components/ntp_snippets/callbacks.h"
#include "components/ntp_snippets/category.h"
#include "components/ntp_snippets/category_rankers/category_ranker.h"
#include "components/ntp_snippets/category_status.h"
#include "components/ntp_snippets/content_suggestions_provider.h"
#include "components/ntp_snippets/logger.h"
#include "components/ntp_snippets/remote/remote_suggestions_scheduler.h"
#include "components/ntp_snippets/user_classifier.h"
#include "components/signin/core/browser/signin_manager.h"
class PrefService;
class PrefRegistrySimple;
namespace favicon {
class LargeIconService;
} // namespace favicon
namespace favicon_base {
struct LargeIconImageResult;
} // namespace favicon_base
namespace ntp_snippets {
class RemoteSuggestionsProvider;
// Retrieves suggestions from a number of ContentSuggestionsProviders and serves
// them grouped into categories. There can be at most one provider per category.
class ContentSuggestionsService : public KeyedService,
public ContentSuggestionsProvider::Observer,
public SigninManagerBase::Observer,
public history::HistoryServiceObserver {
public:
class Observer {
public:
// Fired every time the service receives a new set of data for the given
// |category|, replacing any previously available data (though in most cases
// there will be an overlap and only a few changes within the data). The new
// data is then available through |GetSuggestionsForCategory(category)|.
virtual void OnNewSuggestions(Category category) = 0;
// Fired when the status of a suggestions category changed. Note that for
// some status changes, the UI must update immediately (e.g. to remove
// invalidated suggestions). See comments on the individual CategoryStatus
// values for details.
virtual void OnCategoryStatusChanged(Category category,
CategoryStatus new_status) = 0;
// Fired when a suggestion has been invalidated. The UI must immediately
// clear the suggestion even from open NTPs. Invalidation happens, for
// example, when the content that the suggestion refers to is gone.
// Note that this event may be fired even if the corresponding category is
// not currently AVAILABLE, because open UIs may still be showing the
// suggestion that is to be removed. This event may also be fired for
// |suggestion_id|s that never existed and should be ignored in that case.
virtual void OnSuggestionInvalidated(
const ContentSuggestion::ID& suggestion_id) = 0;
// Fired when the previously sent data is not valid anymore and a refresh
// of all the suggestions is required. Called for example when the sign in
// state changes and personalised suggestions have to be shown or discarded.
virtual void OnFullRefreshRequired() = 0;
// Sent when the service is shutting down. After the service has shut down,
// it will not provide any data anymore, though calling the getters is still
// safe.
virtual void ContentSuggestionsServiceShutdown() = 0;
protected:
virtual ~Observer() = default;
};
enum State {
ENABLED,
DISABLED,
};
ContentSuggestionsService(
State state,
SigninManagerBase* signin_manager, // Can be nullptr in unittests.
history::HistoryService* history_service, // Can be nullptr in unittests.
// Can be nullptr in unittests.
favicon::LargeIconService* large_icon_service,
PrefService* pref_service,
std::unique_ptr<CategoryRanker> category_ranker,
std::unique_ptr<UserClassifier> user_classifier,
std::unique_ptr<RemoteSuggestionsScheduler>
remote_suggestions_scheduler, // Can be nullptr in unittests.
std::unique_ptr<Logger> debug_logger);
~ContentSuggestionsService() override;
// Inherited from KeyedService.
void Shutdown() override;
static void RegisterProfilePrefs(PrefRegistrySimple* registry);
State state() { return state_; }
// Gets all categories for which a provider is registered. The categories may
// or may not be available, see |GetCategoryStatus()|. The order in which the
// categories are returned is the order in which they should be displayed.
std::vector<Category> GetCategories() const;
// Gets the status of a category.
CategoryStatus GetCategoryStatus(Category category) const;
// Gets the meta information of a category.
base::Optional<CategoryInfo> GetCategoryInfo(Category category) const;
// Gets the available suggestions for a category. The result is empty if the
// category is available and empty, but also if the category is unavailable
// for any reason, see |GetCategoryStatus()|.
const std::vector<ContentSuggestion>& GetSuggestionsForCategory(
Category category) const;
// Fetches the image for the suggestion with the given |suggestion_id| and
// runs the |callback|. If that suggestion doesn't exist or the fetch fails,
// the callback gets an empty image. The callback will not be called
// synchronously.
void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
ImageFetchedCallback callback);
// Fetches the favicon from local cache (if larger than or equal to
// |minimum_size_in_pixel|) or from Google server (if there is no icon in the
// cache) and returns the results in the callback. If that suggestion doesn't
// exist or the fetch fails, the callback gets an empty image. The callback
// will not be called synchronously.
void FetchSuggestionFavicon(const ContentSuggestion::ID& suggestion_id,
int minimum_size_in_pixel,
int desired_size_in_pixel,
ImageFetchedCallback callback);
// Dismisses the suggestion with the given |suggestion_id|, if it exists.
// This will not trigger an update through the observers (i.e. providers must
// not call |Observer::OnNewSuggestions|).
void DismissSuggestion(const ContentSuggestion::ID& suggestion_id);
// Dismisses the given |category|, if it exists.
// This will not trigger an update through the observers.
void DismissCategory(Category category);
// Restores all dismissed categories.
// This will not trigger an update through the observers.
void RestoreDismissedCategories();
// Returns whether |category| is dismissed.
bool IsCategoryDismissed(Category category) const;
// Fetches additional contents for the given |category|. If the fetch was
// completed, the given |callback| is called with the updated content.
// This includes new and old data.
// TODO(jkrcal): Consider either renaming this to FetchMore or unify the ways
// to get suggestions to just this async Fetch() API.
void Fetch(const Category& category,
const std::set<std::string>& known_suggestion_ids,
FetchDoneCallback callback);
// Reloads suggestions from all categories, from all providers. If a provider
// naturally has some ability to generate fresh suggestions, it may provide a
// completely new set of suggestions. If the provider has no ability to
// generate fresh suggestions on demand, it may only fill in any vacant space
// by suggestions that were previously not included due to space limits (there
// may be vacant space because of the user dismissing suggestions in the
// meantime).
void ReloadSuggestions();
// Observer accessors.
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
// Registers a new ContentSuggestionsProvider. It must be ensured that at most
// one provider is registered for every category and that this method is
// called only once per provider.
void RegisterProvider(std::unique_ptr<ContentSuggestionsProvider> provider);
// Removes history from the specified time range where the URL matches the
// |filter| from all providers. The data removed depends on the provider. Note
// that the data outside the time range may be deleted, for example
// suggestions, which are based on history from that time range. Providers
// should immediately clear any data related to history from the specified
// time range where the URL matches the |filter|.
void ClearHistory(base::Time begin,
base::Time end,
const base::Callback<bool(const GURL& url)>& filter);
// Removes all suggestions from all caches or internal stores in all
// providers. It does, however, not remove any suggestions from the provider's
// sources, so if its configuration hasn't changed, it might return the same
// results when it fetches the next time. In particular, calling this method
// will not mark any suggestions as dismissed.
void ClearAllCachedSuggestions();
// Only for debugging use through the internals page.
// Retrieves suggestions of the given |category| that have previously been
// dismissed and are still stored in the respective provider. If the
// provider doesn't store dismissed suggestions, the callback receives an
// empty vector. The callback may be called synchronously.
void GetDismissedSuggestionsForDebugging(
Category category,
DismissedSuggestionsCallback callback);
// Only for debugging use through the internals page. Some providers
// internally store a list of dismissed suggestions to prevent them from
// reappearing. This function clears all suggestions of the given |category|
// from such lists, making dismissed suggestions reappear (if the provider
// supports it).
void ClearDismissedSuggestionsForDebugging(Category category);
std::string GetDebugLog() const {
return debug_logger_->GetHumanReadableLog();
}
// Returns true if the remote suggestions provider is enabled.
bool AreRemoteSuggestionsEnabled() const;
// The reference to the RemoteSuggestionsProvider provider should
// only be set by the factory and only used for debugging.
// TODO(jkrcal) The way we deal with the circular dependency feels wrong.
// Consider swapping the dependencies: first constructing all providers, then
// constructing the service (passing the remote provider as arg), finally
// registering the service as an observer of all providers?
// TODO(jkrcal) Move the getter into the scheduler interface (the setter is
// then not needed any more). crbug.com/695447
void set_remote_suggestions_provider(
RemoteSuggestionsProvider* remote_suggestions_provider) {
remote_suggestions_provider_ = remote_suggestions_provider;
}
RemoteSuggestionsProvider* remote_suggestions_provider_for_debugging() {
return remote_suggestions_provider_;
}
// The interface is suited for informing about external events that have
// influence on scheduling remote fetches. Can be nullptr in tests.
RemoteSuggestionsScheduler* remote_suggestions_scheduler() {
return remote_suggestions_scheduler_.get();
}
// Can be nullptr in tests.
// TODO(jkrcal): The getter is only used from the bridge and from
// snippets-internals. Can we get rid of it with the metrics refactoring?
UserClassifier* user_classifier() { return user_classifier_.get(); }
CategoryRanker* category_ranker() { return category_ranker_.get(); }
Logger* debug_logger() { return debug_logger_.get(); }
private:
friend class ContentSuggestionsServiceTest;
// Implementation of ContentSuggestionsProvider::Observer.
void OnNewSuggestions(ContentSuggestionsProvider* provider,
Category category,
std::vector<ContentSuggestion> suggestions) override;
void OnCategoryStatusChanged(ContentSuggestionsProvider* provider,
Category category,
CategoryStatus new_status) override;
void OnSuggestionInvalidated(
ContentSuggestionsProvider* provider,
const ContentSuggestion::ID& suggestion_id) override;
// SigninManagerBase::Observer implementation
void GoogleSigninSucceeded(const std::string& account_id,
const std::string& username) override;
void GoogleSignedOut(const std::string& account_id,
const std::string& username) override;
// history::HistoryServiceObserver implementation.
void OnURLsDeleted(history::HistoryService* history_service,
bool all_history,
bool expired,
const history::URLRows& deleted_rows,
const std::set<GURL>& favicon_urls) override;
void HistoryServiceBeingDeleted(
history::HistoryService* history_service) override;
// Registers the given |provider| for the given |category|, unless it is
// already registered. Returns true if the category was newly registered or
// false if it is dismissed or was present before.
bool TryRegisterProviderForCategory(ContentSuggestionsProvider* provider,
Category category);
void RegisterCategory(Category category,
ContentSuggestionsProvider* provider);
void UnregisterCategory(Category category,
ContentSuggestionsProvider* provider);
// Removes a suggestion from the local store |suggestions_by_category_|, if it
// exists. Returns true if a suggestion was removed.
bool RemoveSuggestionByID(const ContentSuggestion::ID& suggestion_id);
// Fires the OnCategoryStatusChanged event for the given |category|.
void NotifyCategoryStatusChanged(Category category);
void OnSignInStateChanged(bool has_signed_in);
// Re-enables a dismissed category, making querying its provider possible.
void RestoreDismissedCategory(Category category);
void RestoreDismissedCategoriesFromPrefs();
void StoreDismissedCategoriesToPrefs();
// Not implemented for articles. For all other categories, destroys its
// provider, deletes all mentions (except from dismissed list) and notifies
// observers that the category is disabled.
void DestroyCategoryAndItsProvider(Category category);
// Get the domain of the suggestion suitable for fetching the favicon.
GURL GetFaviconDomain(const ContentSuggestion::ID& suggestion_id);
// Initiate the fetch of a favicon from the local cache.
void GetFaviconFromCache(const GURL& publisher_url,
int minimum_size_in_pixel,
int desired_size_in_pixel,
ImageFetchedCallback callback,
bool continue_to_google_server);
// Callbacks for fetching favicons.
void OnGetFaviconFromCacheFinished(
const GURL& publisher_url,
int minimum_size_in_pixel,
int desired_size_in_pixel,
ImageFetchedCallback callback,
bool continue_to_google_server,
const favicon_base::LargeIconImageResult& result);
void OnGetFaviconFromGoogleServerFinished(
const GURL& publisher_url,
int minimum_size_in_pixel,
int desired_size_in_pixel,
ImageFetchedCallback callback,
favicon_base::GoogleFaviconServerRequestStatus status);
// Whether the content suggestions feature is enabled.
State state_;
// All registered providers, owned by the service.
std::vector<std::unique_ptr<ContentSuggestionsProvider>> providers_;
// All registered categories and their providers. A provider may be contained
// multiple times, if it provides multiple categories. The keys of this map
// are exactly the entries of |categories_| and the values are a subset of
// |providers_|.
std::map<Category, ContentSuggestionsProvider*, Category::CompareByID>
providers_by_category_;
// All dismissed categories and their providers. These may be restored by
// RestoreDismissedCategories(). The provider can be null if the dismissed
// category has received no updates since initialisation.
// (see RestoreDismissedCategoriesFromPrefs())
std::map<Category, ContentSuggestionsProvider*, Category::CompareByID>
dismissed_providers_by_category_;
// All current suggestion categories in arbitrary order. This vector contains
// exactly the same categories as |providers_by_category_|.
std::vector<Category> categories_;
// All current suggestions grouped by category. This contains an entry for
// every category in |categories_| whose status is an available status. It may
// contain an empty vector if the category is available but empty (or still
// loading).
std::map<Category, std::vector<ContentSuggestion>, Category::CompareByID>
suggestions_by_category_;
// Observer for the SigninManager. All observers are notified when the signin
// state changes so that they can refresh their list of suggestions.
ScopedObserver<SigninManagerBase, SigninManagerBase::Observer>
signin_observer_;
// Observer for the HistoryService. All providers are notified when history is
// deleted.
ScopedObserver<history::HistoryService, history::HistoryServiceObserver>
history_service_observer_;
base::ObserverList<Observer> observers_;
const std::vector<ContentSuggestion> no_suggestions_;
base::CancelableTaskTracker favicons_task_tracker_;
// Keep a direct reference to this special provider to redirect debugging
// calls to it. If the RemoteSuggestionsProvider is loaded, it is also present
// in |providers_|, otherwise this is a nullptr.
RemoteSuggestionsProvider* remote_suggestions_provider_;
favicon::LargeIconService* large_icon_service_;
PrefService* pref_service_;
// Interface for informing about external events that have influence on
// scheduling remote fetches.
std::unique_ptr<RemoteSuggestionsScheduler> remote_suggestions_scheduler_;
// Classifies the user on the basis of long-term user interactions.
std::unique_ptr<UserClassifier> user_classifier_;
// Provides order for categories.
std::unique_ptr<CategoryRanker> category_ranker_;
std::unique_ptr<Logger> debug_logger_;
DISALLOW_COPY_AND_ASSIGN(ContentSuggestionsService);
};
} // namespace ntp_snippets
#endif // COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTIONS_SERVICE_H_