blob: 39f51e77da8b8ea47089d87d3c940e4d4d19178b [file] [log] [blame]
// Copyright 2013 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.
#include <stddef.h>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "base/callback_forward.h"
#include "base/callback_list.h"
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/scoped_observer.h"
#include "base/strings/string16.h"
#include "components/history/core/browser/history_types.h"
#include "components/history/core/browser/top_sites_observer.h"
#include "components/ntp_tiles/custom_links_manager.h"
#include "components/ntp_tiles/ntp_tile.h"
#include "components/ntp_tiles/popular_sites.h"
#include "components/ntp_tiles/section_type.h"
#include "components/ntp_tiles/tile_source.h"
#include "components/suggestions/proto/suggestions.pb.h"
#include "components/suggestions/suggestions_service.h"
#include "url/gurl.h"
namespace history {
class TopSites;
namespace user_prefs {
class PrefRegistrySyncable;
class PrefService;
namespace ntp_tiles {
class IconCacher;
// Shim interface for SupervisedUserService.
class MostVisitedSitesSupervisor {
struct Whitelist {
base::string16 title;
GURL entry_point;
base::FilePath large_icon_path;
class Observer {
virtual void OnBlockedSitesChanged() = 0;
~Observer() {}
virtual ~MostVisitedSitesSupervisor() {}
// Pass non-null to set observer, or null to remove observer.
// If setting observer, there must not yet be an observer set.
// If removing observer, there must already be one to remove.
// Does not take ownership. Observer must outlive this object.
virtual void SetObserver(Observer* new_observer) = 0;
// If true, |url| should not be shown on the NTP.
virtual bool IsBlocked(const GURL& url) = 0;
// Explicitly-specified sites to show on NTP.
virtual std::vector<Whitelist> GetWhitelists() = 0;
// If true, be conservative about suggesting sites from outside sources.
virtual bool IsChildProfile() = 0;
// Tracks the list of most visited sites.
class MostVisitedSites : public history::TopSitesObserver,
public MostVisitedSitesSupervisor::Observer {
// The observer to be notified when the list of most visited sites changes.
class Observer {
// |sections| must at least contain the PERSONALIZED section.
virtual void OnURLsAvailable(
const std::map<SectionType, NTPTilesVector>& sections) = 0;
virtual void OnIconMadeAvailable(const GURL& site_url) = 0;
virtual ~Observer() {}
// This interface delegates the retrieval of the homepage to the
// platform-specific implementation.
class HomepageClient {
using TitleCallback =
base::OnceCallback<void(const base::Optional<base::string16>& title)>;
virtual ~HomepageClient() = default;
virtual bool IsHomepageTileEnabled() const = 0;
virtual GURL GetHomepageUrl() const = 0;
// TODO( Extract this to another interface.
virtual void QueryHomepageTitle(TitleCallback title_callback) = 0;
// Construct a MostVisitedSites instance.
// |prefs| and |suggestions| are required and may not be null. |top_sites|,
// |popular_sites|, |custom_links|, |supervisor| and |homepage_client| are
// optional and if null, the associated features will be disabled.
MostVisitedSites(PrefService* prefs,
scoped_refptr<history::TopSites> top_sites,
suggestions::SuggestionsService* suggestions,
std::unique_ptr<PopularSites> popular_sites,
std::unique_ptr<CustomLinksManager> custom_links,
std::unique_ptr<IconCacher> icon_cacher,
std::unique_ptr<MostVisitedSitesSupervisor> supervisor);
~MostVisitedSites() override;
// Returns true if this object was created with a non-null provider for the
// given NTP tile source. That source may or may not actually provide tiles,
// depending on its configuration and the priority of different sources.
bool DoesSourceExist(TileSource source) const;
// Returns the corresponding object passed at construction.
history::TopSites* top_sites() { return top_sites_.get(); }
suggestions::SuggestionsService* suggestions() {
return suggestions_service_;
PopularSites* popular_sites() { return popular_sites_.get(); }
MostVisitedSitesSupervisor* supervisor() { return supervisor_.get(); }
// Sets the observer, and immediately fetches the current suggestions.
// Does not take ownership of |observer|, which must outlive this object and
// must not be null.
void SetMostVisitedURLsObserver(Observer* observer, size_t num_sites);
// Sets the client that provides platform-specific homepage preferences.
// When used to replace an existing client, the new client will first be
// used during the construction of a new tile set.
// |client| must not be null and outlive this object.
void SetHomepageClient(std::unique_ptr<HomepageClient> client);
// Requests an asynchronous refresh of the suggestions. Notifies the observer
// if the request resulted in the set of tiles changing.
void Refresh();
// Forces a rebuild of the current tiles.
void RefreshTiles();
// Initializes custom links, which "freezes" the current MV tiles and converts
// them to custom links. Once custom links is initialized, MostVisitedSites
// will return only custom links. If the Most Visited tiles have not been
// loaded yet, does nothing. Custom links must be enabled.
void InitializeCustomLinks();
// Uninitializes custom links and reverts back to regular MV tiles. The
// current custom links will be deleted. Custom links must be enabled.
void UninitializeCustomLinks();
// Returns true if custom links has been initialized and not disabled, false
// otherwise.
bool IsCustomLinksInitialized();
// Enables or disables custom links, but does not (un)initialize them. Called
// when a third-party NTP is being used.
void EnableCustomLinks(bool enable);
// Adds a custom link. If the number of current links is maxed, returns false
// and does nothing. Will initialize custom links if they have not been
// initialized yet. Custom links must be enabled.
bool AddCustomLink(const GURL& url, const base::string16& title);
// Updates the URL and/or title of the custom link specified by |url|. If
// |url| does not exist or |new_url| already exists in the custom link list,
// returns false and does nothing. Will initialize custom links if they have
// not been initialized yet. Custom links must be enabled.
bool UpdateCustomLink(const GURL& url,
const GURL& new_url,
const base::string16& new_title);
// Moves the custom link specified by |url| to the index |new_pos|. If |url|
// does not exist, or |new_pos| is invalid, returns false and does nothing.
// Will initialize custom links if they have not been initialized yet. Custom
// links must be enabled.
bool ReorderCustomLink(const GURL& url, size_t new_pos);
// Deletes the custom link with the specified |url|. If |url| does not exist
// in the custom link list, returns false and does nothing. Will initialize
// custom links if they have not been initialized yet. Custom links must be
// enabled.
bool DeleteCustomLink(const GURL& url);
// Restores the previous state of custom links before the last action that
// modified them. If there was no action, does nothing. If this is undoing the
// first action after initialization, uninitializes the links. Custom links
// must be enabled.
void UndoCustomLinkAction();
void AddOrRemoveBlacklistedUrl(const GURL& url, bool add_url);
void ClearBlacklistedUrls();
// MostVisitedSitesSupervisor::Observer implementation.
void OnBlockedSitesChanged() override;
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
// Workhorse for SaveNewTilesAndNotify. Implemented as a separate static and
// public method for ease of testing.
static NTPTilesVector MergeTiles(NTPTilesVector personal_tiles,
NTPTilesVector whitelist_tiles,
NTPTilesVector popular_tiles);
// This function tries to match the given |host| to a close fit in
// |hosts_to_skip| by removing a prefix that is commonly used to redirect from
// or to mobile pages ( -->
// If this approach fails, the prefix is replaced by another prefix.
// That way, true is returned for if is in |hosts_to_skip|.
static bool IsHostOrMobilePageKnown(
const std::set<std::string>& hosts_to_skip,
const std::string& host);
// Initialize the query to Top Sites. Called if the SuggestionsService
// returned no data.
void InitiateTopSitesQuery();
// If there's a whitelist entry point for the URL, return the large icon path.
base::FilePath GetWhitelistLargeIconPath(const GURL& url);
// Callback for when data is available from TopSites.
void OnMostVisitedURLsAvailable(
const history::MostVisitedURLList& visited_list);
// Callback for when an update is reported by the SuggestionsService.
void OnSuggestionsProfileChanged(
const suggestions::SuggestionsProfile& suggestions_profile);
// Builds the current tileset based on available caches and notifies the
// observer.
void BuildCurrentTiles();
// Same as above the SuggestionsProfile is provided, no need to read cache.
void BuildCurrentTilesGivenSuggestionsProfile(
const suggestions::SuggestionsProfile& suggestions_profile);
// Creates whitelist entry point suggestions whose hosts weren't used yet.
NTPTilesVector CreateWhitelistEntryPointTiles(
const std::set<std::string>& used_hosts,
size_t num_actual_tiles);
// Creates tiles for all popular site sections. Uses |num_actual_tiles| and
// |used_hosts| to restrict results for the PERSONALIZED section.
std::map<SectionType, NTPTilesVector> CreatePopularSitesSections(
const std::set<std::string>& used_hosts,
size_t num_actual_tiles);
// Creates tiles for |sites_vector|. The returned vector will neither contain
// more than |num_max_tiles| nor include sites in |hosts_to_skip|.
NTPTilesVector CreatePopularSitesTiles(
const PopularSites::SitesVector& sites_vector,
const std::set<std::string>& hosts_to_skip,
size_t num_max_tiles);
// Callback for when an update is reported by CustomLinksManager.
void OnCustomLinksChanged();
// Creates tiles for |links| up to |max_num_sites_|. |links| will never exceed
// a certain maximum.
void BuildCustomLinks(const std::vector<CustomLinksManager::Link>& links);
// Initiates a query for the homepage tile if needed and calls
// |SaveTilesAndNotify| in the end.
void InitiateNotificationForNewTiles(NTPTilesVector new_tiles);
// Takes the personal tiles, creates and merges in whitelist and popular tiles
// if appropriate. Calls |SaveTilesAndNotify| at the end.
void MergeMostVisitedTiles(NTPTilesVector personal_tiles);
// Saves the new tiles and notifies the observer if the tiles were actually
// changed.
void SaveTilesAndNotify(NTPTilesVector new_tiles,
std::map<SectionType, NTPTilesVector> sections);
void OnPopularSitesDownloaded(bool success);
void OnIconMadeAvailable(const GURL& site_url);
// Updates the already used hosts and the total tile count based on given new
// tiles. Enforces that the required amount of tiles is not exceeded.
void AddToHostsAndTotalCount(const NTPTilesVector& new_tiles,
std::set<std::string>* hosts,
size_t* total_tile_count) const;
// Adds the homepage as first tile to |tiles| and returns them as new vector.
// Drops existing tiles with the same host as the home page and tiles that
// would exceed the maximum.
NTPTilesVector InsertHomeTile(NTPTilesVector tiles,
const base::string16& title) const;
void OnHomepageTitleDetermined(NTPTilesVector tiles,
const base::Optional<base::string16>& title);
// Returns true if there is a valid homepage that can be pinned as tile.
bool ShouldAddHomeTile() const;
// history::TopSitesObserver implementation.
void TopSitesLoaded(history::TopSites* top_sites) override;
void TopSitesChanged(history::TopSites* top_sites,
ChangeReason change_reason) override;
PrefService* prefs_;
scoped_refptr<history::TopSites> top_sites_;
suggestions::SuggestionsService* suggestions_service_;
std::unique_ptr<PopularSites> const popular_sites_;
std::unique_ptr<CustomLinksManager> const custom_links_;
std::unique_ptr<IconCacher> const icon_cacher_;
std::unique_ptr<MostVisitedSitesSupervisor> supervisor_;
std::unique_ptr<HomepageClient> homepage_client_;
Observer* observer_;
// The maximum number of most visited sites to return.
size_t max_num_sites_;
// False if custom links is disabled and Most Visited sites should be returned
// instead.
bool custom_links_enabled_ = true;
// Number of actions after custom link initialization. Set to -1 and not
// incremented if custom links was not initialized during this session.
int custom_links_action_count_ = -1;
ScopedObserver<history::TopSites, history::TopSitesObserver>
// The main source of personal tiles - either TOP_SITES or SUGGESTIONS_SEVICE.
TileSource mv_source_;
// Current set of tiles. Optional so that the observer can be notified
// whenever it changes, including possibily an initial change from
// !current_tiles_.has_value() to current_tiles_->empty().
base::Optional<NTPTilesVector> current_tiles_;
// For callbacks may be run after destruction, used exclusively for TopSites
// (since it's used to detect whether there's a query in flight).
base::WeakPtrFactory<MostVisitedSites> top_sites_weak_ptr_factory_;
} // namespace ntp_tiles