1 // Copyright (c) 2012 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.
5 #include "chrome/browser/ui/webui/ntp/most_visited_handler.h"
10 #include "base/bind_helpers.h"
11 #include "base/command_line.h"
13 #include "base/memory/scoped_vector.h"
14 #include "base/memory/singleton.h"
15 #include "base/metrics/histogram.h"
16 #include "base/prefs/pref_service.h"
17 #include "base/prefs/scoped_user_pref_update.h"
18 #include "base/strings/string16.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/threading/thread.h"
22 #include "base/values.h"
23 #include "chrome/browser/favicon/fallback_icon_service_factory.h"
24 #include "chrome/browser/favicon/favicon_service_factory.h"
25 #include "chrome/browser/history/top_sites_factory.h"
26 #include "chrome/browser/profiles/profile.h"
27 #include "chrome/browser/thumbnails/thumbnail_list_source.h"
28 #include "chrome/browser/ui/browser.h"
29 #include "chrome/browser/ui/browser_finder.h"
30 #include "chrome/browser/ui/tabs/tab_strip_model.h"
31 #include "chrome/browser/ui/tabs/tab_strip_model_utils.h"
32 #include "chrome/browser/ui/webui/fallback_icon_source.h"
33 #include "chrome/browser/ui/webui/favicon_source.h"
34 #include "chrome/browser/ui/webui/large_icon_source.h"
35 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
36 #include "chrome/browser/ui/webui/ntp/ntp_stats.h"
37 #include "chrome/browser/ui/webui/ntp/thumbnail_source.h"
38 #include "chrome/common/pref_names.h"
39 #include "chrome/common/url_constants.h"
40 #include "components/favicon/core/fallback_icon_service.h"
41 #include "components/favicon/core/favicon_service.h"
42 #include "components/history/core/browser/page_usage_data.h"
43 #include "components/history/core/browser/top_sites.h"
44 #include "components/keyed_service/core/service_access_type.h"
45 #include "components/pref_registry/pref_registry_syncable.h"
46 #include "content/public/browser/navigation_controller.h"
47 #include "content/public/browser/navigation_entry.h"
48 #include "content/public/browser/url_data_source.h"
49 #include "content/public/browser/user_metrics.h"
50 #include "content/public/browser/web_contents.h"
51 #include "content/public/browser/web_ui.h"
54 using base::UserMetricsAction
;
56 MostVisitedHandler::MostVisitedHandler()
57 : scoped_observer_(this),
58 got_first_most_visited_request_(false),
59 most_visited_viewed_(false),
60 user_action_logged_(false),
61 weak_ptr_factory_(this) {
64 MostVisitedHandler::~MostVisitedHandler() {
65 if (!user_action_logged_
&& most_visited_viewed_
) {
66 const GURL ntp_url
= GURL(chrome::kChromeUINewTabURL
);
67 int action_id
= NTP_FOLLOW_ACTION_OTHER
;
68 content::NavigationEntry
* entry
=
69 web_ui()->GetWebContents()->GetController().GetLastCommittedEntry();
70 if (entry
&& (entry
->GetURL() != ntp_url
)) {
72 ui::PageTransitionStripQualifier(entry
->GetTransitionType());
75 UMA_HISTOGRAM_ENUMERATION("NewTabPage.MostVisitedAction", action_id
,
76 NUM_NTP_FOLLOW_ACTIONS
);
80 void MostVisitedHandler::RegisterMessages() {
81 Profile
* profile
= Profile::FromWebUI(web_ui());
82 // Set up our sources for thumbnail and favicon data.
83 content::URLDataSource::Add(profile
, new ThumbnailSource(profile
, false));
84 content::URLDataSource::Add(profile
, new ThumbnailSource(profile
, true));
86 // Set up our sources for top-sites data.
87 content::URLDataSource::Add(profile
, new ThumbnailListSource(profile
));
89 favicon::FaviconService
* favicon_service
=
90 FaviconServiceFactory::GetForProfile(profile
,
91 ServiceAccessType::EXPLICIT_ACCESS
);
92 favicon::FallbackIconService
* fallback_icon_service
=
93 FallbackIconServiceFactory::GetForBrowserContext(profile
);
95 // Register chrome://large-icon as a data source for large icons.
96 content::URLDataSource::Add(profile
,
97 new LargeIconSource(favicon_service
, fallback_icon_service
));
98 content::URLDataSource::Add(profile
,
99 new FallbackIconSource(fallback_icon_service
));
101 // Register chrome://favicon as a data source for favicons.
102 content::URLDataSource::Add(
103 profile
, new FaviconSource(profile
, FaviconSource::FAVICON
));
105 scoped_refptr
<history::TopSites
> top_sites
=
106 TopSitesFactory::GetForProfile(profile
);
108 // TopSites updates itself after a delay. This is especially noticable when
109 // your profile is empty. Ask TopSites to update itself when we're about to
110 // show the new tab page.
111 top_sites
->SyncWithHistory();
113 // Register as TopSitesObserver so that we can update ourselves when the
115 scoped_observer_
.Add(top_sites
.get());
118 // We pre-emptively make a fetch for the most visited pages so we have the
120 StartQueryForMostVisited();
122 web_ui()->RegisterMessageCallback("getMostVisited",
123 base::Bind(&MostVisitedHandler::HandleGetMostVisited
,
124 base::Unretained(this)));
126 // Register ourselves for any most-visited item blacklisting.
127 web_ui()->RegisterMessageCallback("blacklistURLFromMostVisited",
128 base::Bind(&MostVisitedHandler::HandleBlacklistUrl
,
129 base::Unretained(this)));
130 web_ui()->RegisterMessageCallback("removeURLsFromMostVisitedBlacklist",
131 base::Bind(&MostVisitedHandler::HandleRemoveUrlsFromBlacklist
,
132 base::Unretained(this)));
133 web_ui()->RegisterMessageCallback("clearMostVisitedURLsBlacklist",
134 base::Bind(&MostVisitedHandler::HandleClearBlacklist
,
135 base::Unretained(this)));
136 web_ui()->RegisterMessageCallback("mostVisitedAction",
137 base::Bind(&MostVisitedHandler::HandleMostVisitedAction
,
138 base::Unretained(this)));
139 web_ui()->RegisterMessageCallback("mostVisitedSelected",
140 base::Bind(&MostVisitedHandler::HandleMostVisitedSelected
,
141 base::Unretained(this)));
144 void MostVisitedHandler::HandleGetMostVisited(const base::ListValue
* args
) {
145 if (!got_first_most_visited_request_
) {
146 // If our initial data is already here, return it.
148 got_first_most_visited_request_
= true;
150 StartQueryForMostVisited();
154 void MostVisitedHandler::SendPagesValue() {
156 Profile
* profile
= Profile::FromWebUI(web_ui());
157 const base::DictionaryValue
* url_blacklist
=
158 profile
->GetPrefs()->GetDictionary(prefs::kNtpMostVisitedURLsBlacklist
);
159 bool has_blacklisted_urls
= !url_blacklist
->empty();
160 scoped_refptr
<history::TopSites
> ts
=
161 TopSitesFactory::GetForProfile(profile
);
163 has_blacklisted_urls
= ts
->HasBlacklistedItems();
165 base::FundamentalValue
has_blacklisted_urls_value(has_blacklisted_urls
);
166 web_ui()->CallJavascriptFunction("ntp.setMostVisitedPages",
168 has_blacklisted_urls_value
);
169 pages_value_
.reset();
173 void MostVisitedHandler::StartQueryForMostVisited() {
174 scoped_refptr
<history::TopSites
> ts
=
175 TopSitesFactory::GetForProfile(Profile::FromWebUI(web_ui()));
177 ts
->GetMostVisitedURLs(
178 base::Bind(&MostVisitedHandler::OnMostVisitedUrlsAvailable
,
179 weak_ptr_factory_
.GetWeakPtr()), false);
183 void MostVisitedHandler::HandleBlacklistUrl(const base::ListValue
* args
) {
184 std::string url
= base::UTF16ToUTF8(ExtractStringValue(args
));
185 BlacklistUrl(GURL(url
));
188 void MostVisitedHandler::HandleRemoveUrlsFromBlacklist(
189 const base::ListValue
* args
) {
190 DCHECK(args
->GetSize() != 0);
192 for (base::ListValue::const_iterator iter
= args
->begin();
193 iter
!= args
->end(); ++iter
) {
195 bool r
= (*iter
)->GetAsString(&url
);
200 content::RecordAction(UserMetricsAction("MostVisited_UrlRemoved"));
201 scoped_refptr
<history::TopSites
> ts
=
202 TopSitesFactory::GetForProfile(Profile::FromWebUI(web_ui()));
204 ts
->RemoveBlacklistedURL(GURL(url
));
208 void MostVisitedHandler::HandleClearBlacklist(const base::ListValue
* args
) {
209 content::RecordAction(UserMetricsAction("MostVisited_BlacklistCleared"));
211 scoped_refptr
<history::TopSites
> ts
=
212 TopSitesFactory::GetForProfile(Profile::FromWebUI(web_ui()));
214 ts
->ClearBlacklistedURLs();
217 void MostVisitedHandler::HandleMostVisitedAction(const base::ListValue
* args
) {
221 if (!args
->GetDouble(0, &action_id
))
224 UMA_HISTOGRAM_ENUMERATION("NewTabPage.MostVisitedAction",
225 static_cast<int>(action_id
),
226 NUM_NTP_FOLLOW_ACTIONS
);
227 most_visited_viewed_
= true;
228 user_action_logged_
= true;
231 void MostVisitedHandler::HandleMostVisitedSelected(
232 const base::ListValue
* args
) {
233 most_visited_viewed_
= true;
236 void MostVisitedHandler::SetPagesValueFromTopSites(
237 const history::MostVisitedURLList
& data
) {
238 pages_value_
.reset(new base::ListValue
);
240 history::MostVisitedURLList
top_sites(data
);
241 for (size_t i
= 0; i
< top_sites
.size(); i
++) {
242 const history::MostVisitedURL
& url
= top_sites
[i
];
244 // The items which are to be written into |page_value| are also described in
245 // chrome/browser/resources/ntp4/new_tab.js in @typedef for PageData. Please
246 // update it whenever you add or remove any keys here.
247 base::DictionaryValue
* page_value
= new base::DictionaryValue();
248 if (url
.url
.is_empty()) {
249 page_value
->SetBoolean("filler", true);
250 pages_value_
->Append(page_value
);
254 NewTabUI::SetUrlTitleAndDirection(page_value
,
257 pages_value_
->Append(page_value
);
261 void MostVisitedHandler::OnMostVisitedUrlsAvailable(
262 const history::MostVisitedURLList
& data
) {
263 SetPagesValueFromTopSites(data
);
264 if (got_first_most_visited_request_
) {
269 void MostVisitedHandler::TopSitesLoaded(history::TopSites
* top_sites
) {
272 void MostVisitedHandler::TopSitesChanged(history::TopSites
* top_sites
) {
273 // Most visited urls changed, query again.
274 StartQueryForMostVisited();
277 void MostVisitedHandler::BlacklistUrl(const GURL
& url
) {
278 scoped_refptr
<history::TopSites
> ts
=
279 TopSitesFactory::GetForProfile(Profile::FromWebUI(web_ui()));
281 ts
->AddBlacklistedURL(url
);
282 content::RecordAction(UserMetricsAction("MostVisited_UrlBlacklisted"));
285 std::string
MostVisitedHandler::GetDictionaryKeyForUrl(const std::string
& url
) {
286 return base::MD5String(url
);
290 void MostVisitedHandler::RegisterProfilePrefs(
291 user_prefs::PrefRegistrySyncable
* registry
) {
292 registry
->RegisterDictionaryPref(
293 prefs::kNtpMostVisitedURLsBlacklist
,
294 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);