suggestions_page_handler.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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. 4 5#include "chrome/browser/ui/webui/ntp/suggestions_page_handler.h" 6 7#include <math.h> 8#include <vector> 9 10#include "base/bind.h" 11#include "base/bind_helpers.h" 12#include "base/md5.h" 13#include "base/metrics/histogram.h" 14#include "base/strings/string16.h" 15#include "base/strings/utf_string_conversions.h" 16#include "base/threading/thread.h" 17#include "base/values.h" 18#include "chrome/browser/chrome_notification_types.h" 19#include "chrome/browser/history/page_usage_data.h" 20#include "chrome/browser/history/top_sites.h" 21#include "chrome/browser/profiles/profile.h" 22#include "chrome/browser/ui/webui/favicon_source.h" 23#include "chrome/browser/ui/webui/ntp/ntp_stats.h" 24#include "chrome/browser/ui/webui/ntp/suggestions_combiner.h" 25#include "chrome/browser/ui/webui/ntp/suggestions_source_top_sites.h" 26#include "chrome/browser/ui/webui/ntp/thumbnail_source.h" 27#include "chrome/common/url_constants.h" 28#include "components/pref_registry/pref_registry_syncable.h" 29#include "content/public/browser/navigation_controller.h" 30#include "content/public/browser/navigation_entry.h" 31#include "content/public/browser/notification_source.h" 32#include "content/public/browser/url_data_source.h" 33#include "content/public/browser/user_metrics.h" 34#include "content/public/browser/web_contents.h" 35#include "content/public/browser/web_ui.h" 36#include "content/public/common/page_transition_types.h" 37#include "url/gurl.h" 38 39using base::UserMetricsAction; 40 41SuggestionsHandler::SuggestionsHandler() 42 : got_first_suggestions_request_(false), 43 suggestions_viewed_(false), 44 user_action_logged_(false) { 45} 46 47SuggestionsHandler::~SuggestionsHandler() { 48 if (!user_action_logged_ && suggestions_viewed_) { 49 const GURL ntp_url = GURL(chrome::kChromeUINewTabURL); 50 int action_id = NTP_FOLLOW_ACTION_OTHER; 51 content::NavigationEntry* entry = 52 web_ui()->GetWebContents()->GetController().GetLastCommittedEntry(); 53 if (entry && (entry->GetURL() != ntp_url)) { 54 action_id = 55 content::PageTransitionStripQualifier(entry->GetTransitionType()); 56 } 57 58 UMA_HISTOGRAM_ENUMERATION("NewTabPage.SuggestedSitesAction", action_id, 59 NUM_NTP_FOLLOW_ACTIONS); 60 } 61} 62 63void SuggestionsHandler::RegisterMessages() { 64 Profile* profile = Profile::FromWebUI(web_ui()); 65 // Set up our sources for thumbnail and favicon data. 66 content::URLDataSource::Add(profile, new ThumbnailSource(profile, false)); 67 content::URLDataSource::Add( 68 profile, new FaviconSource(profile, FaviconSource::FAVICON)); 69 70 // TODO(georgey) change the source of the web-sites to provide our data. 71 // Initial commit uses top sites as a data source. 72 history::TopSites* top_sites = profile->GetTopSites(); 73 if (top_sites) { 74 // TopSites updates itself after a delay. This is especially noticable when 75 // your profile is empty. Ask TopSites to update itself when we're about to 76 // show the new tab page. 77 top_sites->SyncWithHistory(); 78 79 // Register for notification when TopSites changes so that we can update 80 // ourself. 81 registrar_.Add(this, chrome::NOTIFICATION_TOP_SITES_CHANGED, 82 content::Source<history::TopSites>(top_sites)); 83 } 84 85 // Setup the suggestions sources. 86 SuggestionsCombiner* combiner = new SuggestionsCombiner(this, profile); 87 combiner->AddSource(new SuggestionsSourceTopSites()); 88 suggestions_combiner_.reset(combiner); 89 90 // We pre-emptively make a fetch for suggestions so we have the results 91 // sooner. 92 suggestions_combiner_->FetchItems(profile); 93 94 web_ui()->RegisterMessageCallback("getSuggestions", 95 base::Bind(&SuggestionsHandler::HandleGetSuggestions, 96 base::Unretained(this))); 97 // Register ourselves for any suggestions item blacklisting. 98 web_ui()->RegisterMessageCallback("blacklistURLFromSuggestions", 99 base::Bind(&SuggestionsHandler::HandleBlacklistURL, 100 base::Unretained(this))); 101 web_ui()->RegisterMessageCallback("removeURLsFromSuggestionsBlacklist", 102 base::Bind(&SuggestionsHandler::HandleRemoveURLsFromBlacklist, 103 base::Unretained(this))); 104 web_ui()->RegisterMessageCallback("clearSuggestionsURLsBlacklist", 105 base::Bind(&SuggestionsHandler::HandleClearBlacklist, 106 base::Unretained(this))); 107 web_ui()->RegisterMessageCallback("suggestedSitesAction", 108 base::Bind(&SuggestionsHandler::HandleSuggestedSitesAction, 109 base::Unretained(this))); 110 web_ui()->RegisterMessageCallback("suggestedSitesSelected", 111 base::Bind(&SuggestionsHandler::HandleSuggestedSitesSelected, 112 base::Unretained(this))); 113} 114 115void SuggestionsHandler::HandleGetSuggestions(const base::ListValue* args) { 116 if (!got_first_suggestions_request_) { 117 // If it's the first request we get, return the prefetched data. 118 SendPagesValue(); 119 got_first_suggestions_request_ = true; 120 } else { 121 suggestions_combiner_->FetchItems(Profile::FromWebUI(web_ui())); 122 } 123} 124 125void SuggestionsHandler::OnSuggestionsReady() { 126 // If we got the results as a result of a suggestions request initiated by the 127 // JavaScript then we send back the page values. 128 if (got_first_suggestions_request_) 129 SendPagesValue(); 130} 131 132void SuggestionsHandler::SendPagesValue() { 133 if (suggestions_combiner_->GetPageValues()) { 134 // TODO(georgey) add actual blacklist. 135 bool has_blacklisted_urls = false; 136 base::FundamentalValue has_blacklisted_urls_value(has_blacklisted_urls); 137 web_ui()->CallJavascriptFunction("ntp.setSuggestionsPages", 138 *suggestions_combiner_->GetPageValues(), 139 has_blacklisted_urls_value); 140 } 141} 142 143void SuggestionsHandler::HandleBlacklistURL(const base::ListValue* args) { 144 std::string url = base::UTF16ToUTF8(ExtractStringValue(args)); 145 BlacklistURL(GURL(url)); 146} 147 148void SuggestionsHandler::HandleRemoveURLsFromBlacklist( 149 const base::ListValue* args) { 150 DCHECK_GT(args->GetSize(), 0U); 151 // TODO(georgey) remove URLs from blacklist. 152} 153 154void SuggestionsHandler::HandleClearBlacklist(const base::ListValue* args) { 155 // TODO(georgey) clear blacklist. 156} 157 158void SuggestionsHandler::HandleSuggestedSitesAction( 159 const base::ListValue* args) { 160 DCHECK(args); 161 162 double action_id; 163 if (!args->GetDouble(0, &action_id)) 164 NOTREACHED(); 165 166 UMA_HISTOGRAM_ENUMERATION("NewTabPage.SuggestedSitesAction", 167 static_cast<int>(action_id), 168 NUM_NTP_FOLLOW_ACTIONS); 169 suggestions_viewed_ = true; 170 user_action_logged_ = true; 171} 172 173void SuggestionsHandler::HandleSuggestedSitesSelected( 174 const base::ListValue* args) { 175 suggestions_viewed_ = true; 176} 177 178void SuggestionsHandler::Observe(int type, 179 const content::NotificationSource& source, 180 const content::NotificationDetails& details) { 181 DCHECK_EQ(type, chrome::NOTIFICATION_TOP_SITES_CHANGED); 182 183 // Suggestions urls changed, query again. 184 suggestions_combiner_->FetchItems(Profile::FromWebUI(web_ui())); 185} 186 187void SuggestionsHandler::BlacklistURL(const GURL& url) { 188 // TODO(georgey) blacklist an URL. 189} 190 191std::string SuggestionsHandler::GetDictionaryKeyForURL(const std::string& url) { 192 return base::MD5String(url); 193} 194 195// static 196void SuggestionsHandler::RegisterProfilePrefs( 197 user_prefs::PrefRegistrySyncable* registry) { 198 // TODO(georgey) add user preferences (such as own blacklist) as needed. 199} 200