| 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 |