| Index: components/suggestions/suggestions_service.cc
|
| diff --git a/components/suggestions/suggestions_service.cc b/components/suggestions/suggestions_service.cc
|
| index d76ec667cd6bc3b37e937ed4a845c6d3483bfd97..52932281dcb30dc4dc79788b2ced038c717ceb80 100644
|
| --- a/components/suggestions/suggestions_service.cc
|
| +++ b/components/suggestions/suggestions_service.cc
|
| @@ -22,6 +22,7 @@
|
| #include "components/suggestions/blacklist_store.h"
|
| #include "components/suggestions/image_manager.h"
|
| #include "components/suggestions/suggestions_store.h"
|
| +#include "components/sync_driver/sync_service.h"
|
| #include "components/variations/net/variations_http_headers.h"
|
| #include "google_apis/gaia/gaia_constants.h"
|
| #include "google_apis/gaia/oauth2_token_service.h"
|
| @@ -42,6 +43,37 @@ namespace suggestions {
|
|
|
| namespace {
|
|
|
| +// Establishes the different sync states that matter to SuggestionsService.
|
| +// There are three different concepts in the sync service: initialized, sync
|
| +// enabled and history sync enabled.
|
| +enum SyncState {
|
| + // State: Sync service is not initialized, yet not disabled. History sync
|
| + // state is unknown (since not initialized).
|
| + // Behavior: Does not issue a server request, but serves from cache if
|
| + // available.
|
| + NOT_INITIALIZED_ENABLED,
|
| +
|
| + // State: Sync service is initialized, sync is enabled and history sync is
|
| + // enabled.
|
| + // Behavior: Update suggestions from the server. Serve from cache on timeout.
|
| + INITIALIZED_ENABLED_HISTORY,
|
| +
|
| + // State: Sync service is disabled or history sync is disabled.
|
| + // Behavior: Do not issue a server request. Clear the cache. Serve empty
|
| + // suggestions.
|
| + SYNC_OR_HISTORY_SYNC_DISABLED,
|
| +};
|
| +
|
| +SyncState GetSyncState(sync_driver::SyncService* sync) {
|
| + if (!sync || !sync->CanSyncStart())
|
| + return SYNC_OR_HISTORY_SYNC_DISABLED;
|
| + if (!sync->IsSyncActive() || !sync->ConfigurationDone())
|
| + return NOT_INITIALIZED_ENABLED;
|
| + return sync->GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES)
|
| + ? INITIALIZED_ENABLED_HISTORY
|
| + : SYNC_OR_HISTORY_SYNC_DISABLED;
|
| +}
|
| +
|
| // Used to UMA log the state of the last response from the server.
|
| enum SuggestionsResponseState {
|
| RESPONSE_EMPTY,
|
| @@ -167,44 +199,51 @@ class SuggestionsService::AccessTokenFetcher
|
| SuggestionsService::SuggestionsService(
|
| const SigninManagerBase* signin_manager,
|
| OAuth2TokenService* token_service,
|
| + sync_driver::SyncService* sync_service,
|
| net::URLRequestContextGetter* url_request_context,
|
| scoped_ptr<SuggestionsStore> suggestions_store,
|
| scoped_ptr<ImageManager> thumbnail_manager,
|
| scoped_ptr<BlacklistStore> blacklist_store)
|
| - : url_request_context_(url_request_context),
|
| + : sync_service_(sync_service),
|
| + sync_service_observer_(this),
|
| + url_request_context_(url_request_context),
|
| suggestions_store_(std::move(suggestions_store)),
|
| thumbnail_manager_(std::move(thumbnail_manager)),
|
| blacklist_store_(std::move(blacklist_store)),
|
| scheduling_delay_(TimeDelta::FromSeconds(kDefaultSchedulingDelaySec)),
|
| token_fetcher_(new AccessTokenFetcher(signin_manager, token_service)),
|
| - weak_ptr_factory_(this) {}
|
| + weak_ptr_factory_(this) {
|
| + // |sync_service_| is null if switches::kDisableSync is set (tests use that).
|
| + if (sync_service_)
|
| + sync_service_observer_.Add(sync_service_);
|
| + // Immediately get the current sync state, so we'll flush the cache if
|
| + // necessary.
|
| + OnStateChanged();
|
| +}
|
|
|
| SuggestionsService::~SuggestionsService() {}
|
|
|
| -void SuggestionsService::FetchSuggestionsData(
|
| - SyncState sync_state,
|
| - const ResponseCallback& callback) {
|
| +bool SuggestionsService::FetchSuggestionsData() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| - switch (sync_state) {
|
| - case SYNC_OR_HISTORY_SYNC_DISABLED:
|
| - // Cancel any ongoing request, to stop interacting with the server.
|
| - pending_request_.reset(nullptr);
|
| - suggestions_store_->ClearSuggestions();
|
| - if (!callback.is_null())
|
| - callback.Run(SuggestionsProfile());
|
| - break;
|
| - case INITIALIZED_ENABLED_HISTORY:
|
| - case NOT_INITIALIZED_ENABLED:
|
| - // TODO(treib): For NOT_INITIALIZED_ENABLED, we shouldn't issue a network
|
| - // request. Verify that that won't break anything.
|
| - // Sync is enabled. Serve previously cached suggestions if available, else
|
| - // an empty set of suggestions.
|
| - ServeFromCache(callback);
|
| -
|
| - // Issue a network request to refresh the suggestions in the cache.
|
| - IssueRequestIfNoneOngoing(BuildSuggestionsURL());
|
| - break;
|
| - }
|
| + // If sync state allows, issue a network request to refresh the suggestions.
|
| + if (GetSyncState(sync_service_) != INITIALIZED_ENABLED_HISTORY)
|
| + return false;
|
| + IssueRequestIfNoneOngoing(BuildSuggestionsURL());
|
| + return true;
|
| +}
|
| +
|
| +SuggestionsProfile SuggestionsService::GetSuggestionsDataFromCache() const {
|
| + SuggestionsProfile suggestions;
|
| + // In case of empty cache or error, |suggestions| stays empty.
|
| + suggestions_store_->LoadSuggestions(&suggestions);
|
| + thumbnail_manager_->Initialize(suggestions);
|
| + blacklist_store_->FilterSuggestions(&suggestions);
|
| + return suggestions;
|
| +}
|
| +
|
| +scoped_ptr<SuggestionsService::ResponseCallbackList::Subscription>
|
| +SuggestionsService::AddCallback(const ResponseCallback& callback) {
|
| + return callback_list_.Add(callback);
|
| }
|
|
|
| void SuggestionsService::GetPageThumbnail(const GURL& url,
|
| @@ -220,27 +259,23 @@ void SuggestionsService::GetPageThumbnailWithURL(
|
| GetPageThumbnail(url, callback);
|
| }
|
|
|
| -void SuggestionsService::BlacklistURL(const GURL& candidate_url,
|
| - const ResponseCallback& callback,
|
| - const base::Closure& fail_callback) {
|
| +bool SuggestionsService::BlacklistURL(const GURL& candidate_url) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| - if (!blacklist_store_->BlacklistUrl(candidate_url)) {
|
| - if (!fail_callback.is_null())
|
| - fail_callback.Run();
|
| - return;
|
| - }
|
| + if (!blacklist_store_->BlacklistUrl(candidate_url))
|
| + return false;
|
| +
|
| + callback_list_.Notify(GetSuggestionsDataFromCache());
|
|
|
| - ServeFromCache(callback);
|
| // Blacklist uploads are scheduled on any request completion, so only schedule
|
| // an upload if there is no ongoing request.
|
| if (!pending_request_.get())
|
| ScheduleBlacklistUpload();
|
| +
|
| + return true;
|
| }
|
|
|
| -void SuggestionsService::UndoBlacklistURL(const GURL& url,
|
| - const ResponseCallback& callback,
|
| - const base::Closure& fail_callback) {
|
| +bool SuggestionsService::UndoBlacklistURL(const GURL& url) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| TimeDelta time_delta;
|
| if (blacklist_store_->GetTimeUntilURLReadyForUpload(url, &time_delta) &&
|
| @@ -248,18 +283,17 @@ void SuggestionsService::UndoBlacklistURL(const GURL& url,
|
| blacklist_store_->RemoveUrl(url)) {
|
| // The URL was not yet candidate for upload to the server and could be
|
| // removed from the blacklist.
|
| - ServeFromCache(callback);
|
| - return;
|
| + callback_list_.Notify(GetSuggestionsDataFromCache());
|
| + return true;
|
| }
|
| - if (!fail_callback.is_null())
|
| - fail_callback.Run();
|
| + return false;
|
| }
|
|
|
| -void SuggestionsService::ClearBlacklist(const ResponseCallback& callback) {
|
| +void SuggestionsService::ClearBlacklist() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| blacklist_store_->ClearBlacklist();
|
| + callback_list_.Notify(GetSuggestionsDataFromCache());
|
| IssueRequestIfNoneOngoing(BuildSuggestionsBlacklistClearURL());
|
| - ServeFromCache(callback);
|
| }
|
|
|
| // static
|
| @@ -323,6 +357,26 @@ GURL SuggestionsService::BuildSuggestionsBlacklistClearURL() {
|
| kDeviceType));
|
| }
|
|
|
| +void SuggestionsService::OnStateChanged() {
|
| + switch (GetSyncState(sync_service_)) {
|
| + case SYNC_OR_HISTORY_SYNC_DISABLED:
|
| + // Cancel any ongoing request, to stop interacting with the server.
|
| + pending_request_.reset(nullptr);
|
| + suggestions_store_->ClearSuggestions();
|
| + callback_list_.Notify(SuggestionsProfile());
|
| + break;
|
| + case NOT_INITIALIZED_ENABLED:
|
| + // Keep the cache (if any), but don't refresh.
|
| + break;
|
| + case INITIALIZED_ENABLED_HISTORY:
|
| + // If we have any observers, issue a network request to refresh the
|
| + // suggestions in the cache.
|
| + if (!callback_list_.empty())
|
| + IssueRequestIfNoneOngoing(BuildSuggestionsURL());
|
| + break;
|
| + }
|
| +}
|
| +
|
| void SuggestionsService::SetDefaultExpiryTimestamp(
|
| SuggestionsProfile* suggestions,
|
| int64_t default_timestamp_usec) {
|
| @@ -455,6 +509,8 @@ void SuggestionsService::OnURLFetchComplete(const net::URLFetcher* source) {
|
| LogResponseState(RESPONSE_INVALID);
|
| }
|
|
|
| + callback_list_.Notify(GetSuggestionsDataFromCache());
|
| +
|
| UpdateBlacklistDelay(true);
|
| ScheduleBlacklistUpload();
|
| }
|
| @@ -483,16 +539,6 @@ void SuggestionsService::Shutdown() {
|
| pending_request_.reset(nullptr);
|
| }
|
|
|
| -void SuggestionsService::ServeFromCache(const ResponseCallback& callback) {
|
| - SuggestionsProfile suggestions;
|
| - // In case of empty cache or error, |suggestions| stays empty.
|
| - suggestions_store_->LoadSuggestions(&suggestions);
|
| - thumbnail_manager_->Initialize(suggestions);
|
| - blacklist_store_->FilterSuggestions(&suggestions);
|
| - if (!callback.is_null())
|
| - callback.Run(suggestions);
|
| -}
|
| -
|
| void SuggestionsService::ScheduleBlacklistUpload() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| TimeDelta time_delta;
|
|
|