OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/webui/ntp/most_visited_handler.h" | 5 #include "chrome/browser/ui/webui/ntp/most_visited_handler.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
12 #include "base/md5.h" | 12 #include "base/md5.h" |
13 #include "base/memory/scoped_vector.h" | 13 #include "base/memory/scoped_vector.h" |
14 #include "base/memory/singleton.h" | 14 #include "base/memory/singleton.h" |
15 #include "base/metrics/field_trial.h" | |
16 #include "base/metrics/histogram.h" | 15 #include "base/metrics/histogram.h" |
17 #include "base/prefs/pref_service.h" | 16 #include "base/prefs/pref_service.h" |
18 #include "base/strings/string16.h" | 17 #include "base/strings/string16.h" |
19 #include "base/strings/string_number_conversions.h" | 18 #include "base/strings/string_number_conversions.h" |
20 #include "base/strings/utf_string_conversions.h" | 19 #include "base/strings/utf_string_conversions.h" |
21 #include "base/threading/thread.h" | 20 #include "base/threading/thread.h" |
22 #include "base/values.h" | 21 #include "base/values.h" |
23 #include "chrome/browser/chrome_notification_types.h" | 22 #include "chrome/browser/chrome_notification_types.h" |
| 23 #include "chrome/browser/history/most_visited_tiles_experiment.h" |
24 #include "chrome/browser/history/page_usage_data.h" | 24 #include "chrome/browser/history/page_usage_data.h" |
25 #include "chrome/browser/history/top_sites.h" | 25 #include "chrome/browser/history/top_sites.h" |
26 #include "chrome/browser/prefs/scoped_user_pref_update.h" | 26 #include "chrome/browser/prefs/scoped_user_pref_update.h" |
27 #include "chrome/browser/profiles/profile.h" | 27 #include "chrome/browser/profiles/profile.h" |
28 #include "chrome/browser/ui/browser.h" | 28 #include "chrome/browser/ui/browser.h" |
29 #include "chrome/browser/ui/browser_finder.h" | 29 #include "chrome/browser/ui/browser_finder.h" |
30 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 30 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 31 #include "chrome/browser/ui/tabs/tab_strip_model_utils.h" |
31 #include "chrome/browser/ui/webui/favicon_source.h" | 32 #include "chrome/browser/ui/webui/favicon_source.h" |
32 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h" | 33 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h" |
33 #include "chrome/browser/ui/webui/ntp/ntp_stats.h" | 34 #include "chrome/browser/ui/webui/ntp/ntp_stats.h" |
34 #include "chrome/browser/ui/webui/ntp/thumbnail_source.h" | 35 #include "chrome/browser/ui/webui/ntp/thumbnail_source.h" |
35 #include "chrome/common/pref_names.h" | 36 #include "chrome/common/pref_names.h" |
36 #include "chrome/common/url_constants.h" | 37 #include "chrome/common/url_constants.h" |
37 #include "components/user_prefs/pref_registry_syncable.h" | 38 #include "components/user_prefs/pref_registry_syncable.h" |
38 #include "content/public/browser/navigation_controller.h" | 39 #include "content/public/browser/navigation_controller.h" |
39 #include "content/public/browser/navigation_entry.h" | 40 #include "content/public/browser/navigation_entry.h" |
40 #include "content/public/browser/notification_source.h" | 41 #include "content/public/browser/notification_source.h" |
41 #include "content/public/browser/url_data_source.h" | 42 #include "content/public/browser/url_data_source.h" |
42 #include "content/public/browser/user_metrics.h" | 43 #include "content/public/browser/user_metrics.h" |
43 #include "content/public/browser/web_contents.h" | 44 #include "content/public/browser/web_contents.h" |
44 #include "content/public/browser/web_ui.h" | 45 #include "content/public/browser/web_ui.h" |
45 #include "grit/chromium_strings.h" | 46 #include "grit/chromium_strings.h" |
46 #include "grit/generated_resources.h" | 47 #include "grit/generated_resources.h" |
47 #include "grit/locale_settings.h" | 48 #include "grit/locale_settings.h" |
48 #include "ui/base/l10n/l10n_util.h" | 49 #include "ui/base/l10n/l10n_util.h" |
49 #include "url/gurl.h" | 50 #include "url/gurl.h" |
50 | 51 |
51 using content::UserMetricsAction; | 52 using content::UserMetricsAction; |
52 | 53 |
53 namespace { | |
54 | |
55 // Constants for the most visited tile placement field trial. | |
56 const char kMostVisitedFieldTrialName[] = "MostVisitedTilePlacement"; | |
57 const char kTabsGroupName[] = "DontShowOpenTabs"; | |
58 | |
59 // Minimum number of suggestions that |pages_value_| must hold for the Most | |
60 // Visited Field Trial to remove a URL if already open in the browser. | |
61 const size_t kMinUrlSuggestions = 8; | |
62 | |
63 // Creates a set containing the canonical URLs of the currently open tabs. | |
64 void GetOpenUrls(const TabStripModel& tabs, | |
65 const history::TopSites& ts, | |
66 std::set<std::string>* urls) { | |
67 for (int i = 0; i < tabs.count(); ++i) { | |
68 content::WebContents* web_contents = tabs.GetWebContentsAt(i); | |
69 if (web_contents) | |
70 urls->insert(ts.GetCanonicalURLString(web_contents->GetURL())); | |
71 } | |
72 } | |
73 | |
74 } // namespace | |
75 | |
76 MostVisitedHandler::MostVisitedHandler() | 54 MostVisitedHandler::MostVisitedHandler() |
77 : weak_ptr_factory_(this), | 55 : weak_ptr_factory_(this), |
78 got_first_most_visited_request_(false), | 56 got_first_most_visited_request_(false), |
79 most_visited_viewed_(false), | 57 most_visited_viewed_(false), |
80 user_action_logged_(false) { | 58 user_action_logged_(false) { |
81 } | 59 } |
82 | 60 |
83 MostVisitedHandler::~MostVisitedHandler() { | 61 MostVisitedHandler::~MostVisitedHandler() { |
84 if (!user_action_logged_ && most_visited_viewed_) { | 62 if (!user_action_logged_ && most_visited_viewed_) { |
85 const GURL ntp_url = GURL(chrome::kChromeUINewTabURL); | 63 const GURL ntp_url = GURL(chrome::kChromeUINewTabURL); |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 void MostVisitedHandler::SendPagesValue() { | 141 void MostVisitedHandler::SendPagesValue() { |
164 if (pages_value_) { | 142 if (pages_value_) { |
165 Profile* profile = Profile::FromWebUI(web_ui()); | 143 Profile* profile = Profile::FromWebUI(web_ui()); |
166 const DictionaryValue* url_blacklist = | 144 const DictionaryValue* url_blacklist = |
167 profile->GetPrefs()->GetDictionary(prefs::kNtpMostVisitedURLsBlacklist); | 145 profile->GetPrefs()->GetDictionary(prefs::kNtpMostVisitedURLsBlacklist); |
168 bool has_blacklisted_urls = !url_blacklist->empty(); | 146 bool has_blacklisted_urls = !url_blacklist->empty(); |
169 history::TopSites* ts = profile->GetTopSites(); | 147 history::TopSites* ts = profile->GetTopSites(); |
170 if (ts) { | 148 if (ts) { |
171 has_blacklisted_urls = ts->HasBlacklistedItems(); | 149 has_blacklisted_urls = ts->HasBlacklistedItems(); |
172 | 150 |
173 // The following experiment removes recommended URLs if a matching URL is | 151 MaybeRemovePageValues(); |
174 // already open in the Browser. Note: this targets only the | |
175 // top-level of sites i.e. if www.foo.com/bar is open in browser, and | |
176 // www.foo.com is a recommended URL, www.foo.com will still appear on the | |
177 // next NTP open. | |
178 if (base::FieldTrialList::FindFullName(kMostVisitedFieldTrialName) == | |
179 kTabsGroupName) { | |
180 RemovePageValuesMatchingOpenTabs(); | |
181 } | |
182 } | 152 } |
183 | 153 |
184 base::FundamentalValue has_blacklisted_urls_value(has_blacklisted_urls); | 154 base::FundamentalValue has_blacklisted_urls_value(has_blacklisted_urls); |
185 web_ui()->CallJavascriptFunction("ntp.setMostVisitedPages", | 155 web_ui()->CallJavascriptFunction("ntp.setMostVisitedPages", |
186 *pages_value_, | 156 *pages_value_, |
187 has_blacklisted_urls_value); | 157 has_blacklisted_urls_value); |
188 pages_value_.reset(); | 158 pages_value_.reset(); |
189 } | 159 } |
190 } | 160 } |
191 | 161 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
246 void MostVisitedHandler::HandleMostVisitedSelected( | 216 void MostVisitedHandler::HandleMostVisitedSelected( |
247 const base::ListValue* args) { | 217 const base::ListValue* args) { |
248 most_visited_viewed_ = true; | 218 most_visited_viewed_ = true; |
249 } | 219 } |
250 | 220 |
251 void MostVisitedHandler::SetPagesValueFromTopSites( | 221 void MostVisitedHandler::SetPagesValueFromTopSites( |
252 const history::MostVisitedURLList& data) { | 222 const history::MostVisitedURLList& data) { |
253 pages_value_.reset(new ListValue); | 223 pages_value_.reset(new ListValue); |
254 | 224 |
255 history::MostVisitedURLList top_sites(data); | 225 history::MostVisitedURLList top_sites(data); |
256 history::TopSites::MaybeShuffle(&top_sites); | 226 history::MostVisitedTilesExperiment::MaybeShuffle(&top_sites); |
257 | 227 |
258 for (size_t i = 0; i < top_sites.size(); i++) { | 228 for (size_t i = 0; i < top_sites.size(); i++) { |
259 const history::MostVisitedURL& url = top_sites[i]; | 229 const history::MostVisitedURL& url = top_sites[i]; |
260 DictionaryValue* page_value = new DictionaryValue(); | 230 DictionaryValue* page_value = new DictionaryValue(); |
261 if (url.url.is_empty()) { | 231 if (url.url.is_empty()) { |
262 page_value->SetBoolean("filler", true); | 232 page_value->SetBoolean("filler", true); |
263 pages_value_->Append(page_value); | 233 pages_value_->Append(page_value); |
264 continue; | 234 continue; |
265 } | 235 } |
266 | 236 |
(...skipping 25 matching lines...) Expand all Loading... |
292 history::TopSites* ts = Profile::FromWebUI(web_ui())->GetTopSites(); | 262 history::TopSites* ts = Profile::FromWebUI(web_ui())->GetTopSites(); |
293 if (ts) | 263 if (ts) |
294 ts->AddBlacklistedURL(url); | 264 ts->AddBlacklistedURL(url); |
295 content::RecordAction(UserMetricsAction("MostVisited_UrlBlacklisted")); | 265 content::RecordAction(UserMetricsAction("MostVisited_UrlBlacklisted")); |
296 } | 266 } |
297 | 267 |
298 std::string MostVisitedHandler::GetDictionaryKeyForUrl(const std::string& url) { | 268 std::string MostVisitedHandler::GetDictionaryKeyForUrl(const std::string& url) { |
299 return base::MD5String(url); | 269 return base::MD5String(url); |
300 } | 270 } |
301 | 271 |
302 void MostVisitedHandler::RemovePageValuesMatchingOpenTabs() { | 272 void MostVisitedHandler::MaybeRemovePageValues() { |
| 273 // The code below uses APIs not available on Android and the experiment should |
| 274 // not run there. |
303 #if !defined(OS_ANDROID) | 275 #if !defined(OS_ANDROID) |
| 276 if (!history::MostVisitedTilesExperiment::IsDontShowOpenURLsEnabled()) |
| 277 return; |
| 278 |
304 TabStripModel* tab_strip_model = chrome::FindBrowserWithWebContents( | 279 TabStripModel* tab_strip_model = chrome::FindBrowserWithWebContents( |
305 web_ui()->GetWebContents())->tab_strip_model(); | 280 web_ui()->GetWebContents())->tab_strip_model(); |
306 history::TopSites* ts = Profile::FromWebUI(web_ui())->GetTopSites(); | 281 history::TopSites* top_sites = Profile::FromWebUI(web_ui())->GetTopSites(); |
307 if (!tab_strip_model || !ts) { | 282 if (!tab_strip_model || !top_sites) { |
308 NOTREACHED(); | 283 NOTREACHED(); |
309 return; | 284 return; |
310 } | 285 } |
311 | 286 |
312 // Iterate through most visited suggestions and remove pages already open in | |
313 // current browser, making sure to not drop below 8 suggestions. | |
314 std::set<std::string> open_urls; | 287 std::set<std::string> open_urls; |
315 GetOpenUrls(*tab_strip_model, *ts, &open_urls); | 288 chrome::GetOpenUrls(*tab_strip_model, *top_sites, &open_urls); |
316 size_t i = 0; | 289 history::MostVisitedTilesExperiment::RemovePageValuesMatchingOpenTabs( |
317 while (i < pages_value_->GetSize() && | 290 open_urls, |
318 pages_value_->GetSize() > kMinUrlSuggestions) { | 291 pages_value_.get()); |
319 base::DictionaryValue* page_value; | |
320 std::string url; | |
321 if (pages_value_->GetDictionary(i, &page_value) && | |
322 page_value->GetString("url", &url) && | |
323 open_urls.count(url) != 0) { | |
324 pages_value_->Remove(*page_value, &i); | |
325 } else { | |
326 ++i; | |
327 } | |
328 } | |
329 #endif | 292 #endif |
330 } | 293 } |
331 | 294 |
332 // static | 295 // static |
333 void MostVisitedHandler::RegisterProfilePrefs( | 296 void MostVisitedHandler::RegisterProfilePrefs( |
334 user_prefs::PrefRegistrySyncable* registry) { | 297 user_prefs::PrefRegistrySyncable* registry) { |
335 registry->RegisterDictionaryPref( | 298 registry->RegisterDictionaryPref( |
336 prefs::kNtpMostVisitedURLsBlacklist, | 299 prefs::kNtpMostVisitedURLsBlacklist, |
337 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | 300 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
338 } | 301 } |
OLD | NEW |