blob: a4ecd027ce7efebd9d85dbb6042e2d4bdbccdbf7 [file] [log] [blame]
// Copyright 2019 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 CHROME_BROWSER_SEARCH_SEARCH_SUGGEST_SEARCH_SUGGEST_SERVICE_H_
#define CHROME_BROWSER_SEARCH_SEARCH_SUGGEST_SEARCH_SUGGEST_SERVICE_H_
#include <memory>
#include <string>
#include "base/observer_list.h"
#include "base/optional.h"
#include "chrome/browser/search/search_suggest/search_suggest_data.h"
#include "chrome/browser/search/search_suggest/search_suggest_loader.h"
#include "chrome/browser/search/search_suggest/search_suggest_service_observer.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
class Profile;
namespace signin {
class IdentityManager;
} // namespace signin
// A service that downloads, caches, and hands out SearchSuggestData. It never
// initiates a download automatically, only when Refresh is called. When the
// user signs in or out, the cached value is cleared.
class SearchSuggestService : public KeyedService {
public:
static bool IsEnabled();
SearchSuggestService(Profile* profile,
signin::IdentityManager* identity_manager,
std::unique_ptr<SearchSuggestLoader> loader);
~SearchSuggestService() override;
// KeyedService implementation.
void Shutdown() override;
// Returns the currently cached SearchSuggestData, if any.
// Virtual for testing.
virtual const base::Optional<SearchSuggestData>& search_suggest_data() const;
virtual const SearchSuggestLoader::Status& search_suggest_status() const;
// Determines if a request for search suggestions should be made. If a request
// should not be made immediately call SearchSuggestDataLoaded with the
// reason. Otherwise requests an asynchronous refresh from the network. After
// the update completes, regardless of success, OnSearchSuggestDataUpdated
// will be called on the observers.
// Virtual for testing.
virtual void Refresh();
// Add/remove observers. All observers must unregister themselves before the
// SearchSuggestService is destroyed.
void AddObserver(SearchSuggestServiceObserver* observer);
void RemoveObserver(SearchSuggestServiceObserver* observer);
// Register prefs associated with the NTP.
static void RegisterProfilePrefs(PrefRegistrySimple* registry);
// Add the task_id to the blocklist stored in user prefs. Overrides any
// existing entry for the given task_id.
//
// A task_id represents a category of searches such as "Camping", a
// task_version represents the selection criteria used to generate the
// suggestion.
void BlocklistSearchSuggestion(int task_version, long task_id);
// Add the hash to the list of hashes for the task_id. Stored as a
// dict of task_ids to lists of hashes in user prefs.
//
// A task_id represents a category of searches such as "Camping", a hash
// is a specific search within the category such as "Camping equipment", and
// a task_version represents the selection criteria used ti generate the
// suggestion.
void BlocklistSearchSuggestionWithHash(int task_version,
long task_id,
const uint8_t hash[4]);
// Issue a new request with the selected suggestion appended to the blocklist
// but NOT stored in user prefs. This prevents a race condition where the
// request completes before the data server side is updated to reflect the
// selection, resulting in the same suggestion appearing in the next set.
void SearchSuggestionSelected(int task_version,
long task_id,
const uint8_t hash[4]);
// Opt the current profile out of seeing search suggestions. Requests will
// no longer be made.
void OptOutOfSearchSuggestions();
SearchSuggestLoader* loader_for_testing() { return loader_.get(); }
// Returns the string representation of the suggestions blocklist in the form:
// "task_id1:hash1,hash2,hash3;task_id2;task_id3:hash1,hash2".
std::string GetBlocklistAsString();
// Called when suggestions are displayed on the NTP, clears the cached data
// and updates timestamps and impression counts.
// Virtual for testing.
virtual void SuggestionsDisplayed();
protected:
// Called when a Refresh() is requested. If |status|==OK, |data| will contain
// the fetched data. Otherwise |data| will be nullopt and |status| will
// indicate if the request failed or the reason it was not sent.
//
// If the |status|==FATAL_ERROR freeze future requests until the request
// freeze interval has elapsed.
void SearchSuggestDataLoaded(SearchSuggestLoader::Status status,
const base::Optional<SearchSuggestData>& data);
private:
class SigninObserver;
void SigninStatusChanged();
// Either calls SearchSuggestLoader::Load with |blocklist| or immediately
// calls SearchSuggestDataLoaded with the reason a request was not made.
void MaybeLoadWithBlocklist(const std::string& blocklist);
void NotifyObservers();
// Returns true if the number of impressions has reached the maxmium allowed
// for the impression interval (e.g. 4 impressions / 12 hours), and false
// otherwise.
bool ImpressionCapReached();
// Returns true if requests are frozen and request freeze time interval has
// not elapsed, false otherwise.
//
// Requests are frozen on any request that results in a FATAL_ERROR.
bool RequestsFrozen();
std::unique_ptr<SearchSuggestLoader> loader_;
std::unique_ptr<SigninObserver> signin_observer_;
Profile* profile_;
base::ObserverList<SearchSuggestServiceObserver, true>::Unchecked observers_;
base::Optional<SearchSuggestData> search_suggest_data_;
SearchSuggestLoader::Status search_suggest_status_;
};
#endif // CHROME_BROWSER_SEARCH_SEARCH_SUGGEST_SEARCH_SUGGEST_SERVICE_H_