172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/ui/webui/most_visited_handler.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <set>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/callback.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/command_line.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/md5.h"
12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_vector.h"
13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/singleton.h"
143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string16.h"
153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h"
163f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread.h"
17dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/utf_string_conversions.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/values.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/page_usage_data.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/top_sites.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/metrics/user_metrics.h"
223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/prefs/pref_service.h"
23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/prefs/scoped_user_pref_update.h"
2421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
25dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/ui/webui/chrome_url_data_manager.h"
26dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/ui/webui/favicon_source.h"
27dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/ui/webui/new_tab_ui.h"
28dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/ui/webui/thumbnail_source.h"
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/pref_names.h"
30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/common/url_constants.h"
31dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_source.h"
33ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_type.h"
343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "googleurl/src/gurl.h"
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/chromium_strings.h"
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h"
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/locale_settings.h"
3872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h"
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The number of most visited pages we show.
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst size_t kMostVisitedPages = 8;
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The number of days of history we consider for most visited entries.
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kMostVisitedScope = 90;
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// This struct is used when getting the pre-populated pages in case the user
513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// hasn't filled up his most visited pages.
523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstruct MostVisitedHandler::MostVisitedPage {
533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  string16 title;
543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  GURL url;
553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  GURL thumbnail_url;
563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  GURL favicon_url;
573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick};
583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochMostVisitedHandler::MostVisitedHandler()
60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    : got_first_most_visited_request_(false) {
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
633345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickMostVisitedHandler::~MostVisitedHandler() {
643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
6672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenWebUIMessageHandler* MostVisitedHandler::Attach(WebUI* web_ui) {
6772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  Profile* profile = web_ui->GetProfile();
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Set up our sources for thumbnail and favicon data.
69dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  ThumbnailSource* thumbnail_src = new ThumbnailSource(profile);
7072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  profile->GetChromeURLDataManager()->AddDataSource(thumbnail_src);
7172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  profile->GetChromeURLDataManager()->AddDataSource(new FaviconSource(profile));
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Get notifications when history is cleared.
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this, NotificationType::HISTORY_URLS_DELETED,
7672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                 Source<Profile>(profile));
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  WebUIMessageHandler* result = WebUIMessageHandler::Attach(web_ui);
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We pre-emptively make a fetch for the most visited pages so we have the
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // results sooner.
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  StartQueryForMostVisited();
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid MostVisitedHandler::RegisterMessages() {
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Register ourselves as the handler for the "mostvisited" message from
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Javascript.
8972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  web_ui_->RegisterMessageCallback("getMostVisited",
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewCallback(this, &MostVisitedHandler::HandleGetMostVisited));
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Register ourselves for any most-visited item blacklisting.
9372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  web_ui_->RegisterMessageCallback("blacklistURLFromMostVisited",
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewCallback(this, &MostVisitedHandler::HandleBlacklistURL));
9572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  web_ui_->RegisterMessageCallback("removeURLsFromMostVisitedBlacklist",
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewCallback(this, &MostVisitedHandler::HandleRemoveURLsFromBlacklist));
9772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  web_ui_->RegisterMessageCallback("clearMostVisitedURLsBlacklist",
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewCallback(this, &MostVisitedHandler::HandleClearBlacklist));
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Register ourself for pinned URL messages.
10172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  web_ui_->RegisterMessageCallback("addPinnedURL",
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewCallback(this, &MostVisitedHandler::HandleAddPinnedURL));
10372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  web_ui_->RegisterMessageCallback("removePinnedURL",
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewCallback(this, &MostVisitedHandler::HandleRemovePinnedURL));
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid MostVisitedHandler::HandleGetMostVisited(const ListValue* args) {
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!got_first_most_visited_request_) {
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If our intial data is already here, return it.
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SendPagesValue();
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    got_first_most_visited_request_ = true;
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    StartQueryForMostVisited();
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid MostVisitedHandler::SendPagesValue() {
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (pages_value_.get()) {
119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    Profile* profile = web_ui_->GetProfile();
120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const DictionaryValue* url_blacklist =
121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        profile->GetPrefs()->GetDictionary(prefs::kNTPMostVisitedURLsBlacklist);
122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    bool has_blacklisted_urls = !url_blacklist->empty();
123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    history::TopSites* ts = profile->GetTopSites();
12472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (ts)
12572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      has_blacklisted_urls = ts->HasBlacklistedItems();
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    FundamentalValue first_run(IsFirstRun());
127731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    FundamentalValue has_blacklisted_urls_value(has_blacklisted_urls);
128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    web_ui_->CallJavascriptFunction("mostVisitedPages",
1293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                    *(pages_value_.get()),
1303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                    first_run,
131731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                    has_blacklisted_urls_value);
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    pages_value_.reset();
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid MostVisitedHandler::StartQueryForMostVisited() {
13772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Use TopSites.
13872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  history::TopSites* ts = web_ui_->GetProfile()->GetTopSites();
13972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (ts) {
14072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ts->GetMostVisitedURLs(
14172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        &topsites_consumer_,
14272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        NewCallback(this, &MostVisitedHandler::OnMostVisitedURLsAvailable));
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid MostVisitedHandler::HandleBlacklistURL(const ListValue* args) {
147ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string url = UTF16ToUTF8(ExtractStringValue(args));
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BlacklistURL(GURL(url));
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid MostVisitedHandler::HandleRemoveURLsFromBlacklist(const ListValue* args) {
1523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(args->GetSize() != 0);
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (ListValue::const_iterator iter = args->begin();
1553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick       iter != args->end(); ++iter) {
1563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    std::string url;
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool r = (*iter)->GetAsString(&url);
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!r) {
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED();
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UserMetrics::RecordAction(UserMetricsAction("MostVisited_UrlRemoved"),
16372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                              web_ui_->GetProfile());
16472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    history::TopSites* ts = web_ui_->GetProfile()->GetTopSites();
16572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (ts)
16672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      ts->RemoveBlacklistedURL(GURL(url));
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid MostVisitedHandler::HandleClearBlacklist(const ListValue* args) {
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UserMetrics::RecordAction(UserMetricsAction("MostVisited_BlacklistCleared"),
17272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                            web_ui_->GetProfile());
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
17472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  history::TopSites* ts = web_ui_->GetProfile()->GetTopSites();
17572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (ts)
17672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ts->ClearBlacklistedURLs();
1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid MostVisitedHandler::HandleAddPinnedURL(const ListValue* args) {
1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_EQ(5U, args->GetSize()) << "Wrong number of params to addPinnedURL";
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MostVisitedPage mvp;
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string tmp_string;
1833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  string16 tmp_string16;
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int index;
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  bool r = args->GetString(0, &tmp_string);
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(r) << "Missing URL in addPinnedURL from the NTP Most Visited.";
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  mvp.url = GURL(tmp_string);
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  r = args->GetString(1, &tmp_string16);
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(r) << "Missing title in addPinnedURL from the NTP Most Visited.";
1923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  mvp.title = tmp_string16;
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  r = args->GetString(2, &tmp_string);
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(r) << "Failed to read the favicon URL in addPinnedURL from the NTP "
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            << "Most Visited.";
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!tmp_string.empty())
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    mvp.favicon_url = GURL(tmp_string);
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  r = args->GetString(3, &tmp_string);
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(r) << "Failed to read the thumbnail URL in addPinnedURL from the NTP "
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            << "Most Visited.";
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!tmp_string.empty())
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    mvp.thumbnail_url = GURL(tmp_string);
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  r = args->GetString(4, &tmp_string);
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(r) << "Missing index in addPinnedURL from the NTP Most Visited.";
2083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  base::StringToInt(tmp_string, &index);
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddPinnedURL(mvp, index);
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid MostVisitedHandler::AddPinnedURL(const MostVisitedPage& page, int index) {
21472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  history::TopSites* ts = web_ui_->GetProfile()->GetTopSites();
21572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (ts)
21672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ts->AddPinnedURL(page.url, index);
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid MostVisitedHandler::HandleRemovePinnedURL(const ListValue* args) {
220ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string url = UTF16ToUTF8(ExtractStringValue(args));
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RemovePinnedURL(GURL(url));
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid MostVisitedHandler::RemovePinnedURL(const GURL& url) {
22572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  history::TopSites* ts = web_ui_->GetProfile()->GetTopSites();
22672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (ts)
22772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ts->RemovePinnedURL(url);
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool MostVisitedHandler::GetPinnedURLAtIndex(int index,
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             MostVisitedPage* page) {
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This iterates over all the pinned URLs. It might seem like it is worth
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // having a map from the index to the item but the number of items is limited
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // to the number of items the most visited section is showing on the NTP so
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // this will be fast enough for now.
236ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  PrefService* prefs = web_ui_->GetProfile()->GetPrefs();
237ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const DictionaryValue* pinned_urls =
238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      prefs->GetDictionary(prefs::kNTPMostVisitedPinnedURLs);
239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (DictionaryValue::key_iterator it = pinned_urls->begin_keys();
240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      it != pinned_urls->end_keys(); ++it) {
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Value* value;
242ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (pinned_urls->GetWithoutPathExpansion(*it, &value)) {
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!value->IsType(DictionaryValue::TYPE_DICTIONARY)) {
2443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        // Moved on to TopSites and now going back.
245ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        DictionaryPrefUpdate update(prefs, prefs::kNTPMostVisitedPinnedURLs);
246ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        update.Get()->Clear();
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      int dict_index;
251ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      const DictionaryValue* dict = static_cast<DictionaryValue*>(value);
2523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (dict->GetInteger("index", &dict_index) && dict_index == index) {
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // The favicon and thumbnail URLs may be empty.
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        std::string tmp_string;
2553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        if (dict->GetString("faviconUrl", &tmp_string))
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          page->favicon_url = GURL(tmp_string);
2573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        if (dict->GetString("thumbnailUrl", &tmp_string))
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          page->thumbnail_url = GURL(tmp_string);
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        if (dict->GetString("url", &tmp_string))
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          page->url = GURL(tmp_string);
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        else
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return false;
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        return dict->GetString("title", &page->title);
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED() << "DictionaryValue iterators are filthy liars.";
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid MostVisitedHandler::SetPagesValueFromTopSites(
2763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const history::MostVisitedURLList& data) {
2773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  pages_value_.reset(new ListValue);
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < data.size(); i++) {
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const history::MostVisitedURL& url = data[i];
2803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DictionaryValue* page_value = new DictionaryValue();
2813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (url.url.is_empty()) {
2823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      page_value->SetBoolean("filler", true);
2833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      pages_value_->Append(page_value);
2843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      continue;
2853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
2863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    NewTabUI::SetURLTitleAndDirection(page_value,
2883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                      url.title,
2893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                      url.url);
2903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!url.favicon_url.is_empty())
2913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      page_value->SetString("faviconUrl", url.favicon_url.spec());
2923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Special case for prepopulated pages: thumbnailUrl is different from url.
2943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (url.url.spec() == l10n_util::GetStringUTF8(IDS_CHROME_WELCOME_URL)) {
2953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      page_value->SetString("thumbnailUrl",
2963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          "chrome://theme/IDR_NEWTAB_CHROME_WELCOME_PAGE_THUMBNAIL");
2973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    } else if (url.url.spec() ==
2983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick               l10n_util::GetStringUTF8(IDS_THEMES_GALLERY_URL)) {
2993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      page_value->SetString("thumbnailUrl",
3003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          "chrome://theme/IDR_NEWTAB_THEMES_GALLERY_THUMBNAIL");
3013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
3023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
30372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    history::TopSites* ts = web_ui_->GetProfile()->GetTopSites();
304513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (ts && ts->IsURLPinned(url.url))
3053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      page_value->SetBoolean("pinned", true);
3063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    pages_value_->Append(page_value);
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid MostVisitedHandler::OnMostVisitedURLsAvailable(
311513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const history::MostVisitedURLList& data) {
3123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  SetPagesValueFromTopSites(data);
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (got_first_most_visited_request_) {
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SendPagesValue();
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool MostVisitedHandler::IsFirstRun() {
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If we found no pages we treat this as the first run.
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool first_run = NewTabUI::NewTabHTMLSource::first_run() &&
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      pages_value_->GetSize() ==
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          MostVisitedHandler::GetPrePopulatedPages().size();
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // but first_run should only be true once.
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NewTabUI::NewTabHTMLSource::set_first_run(false);
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return first_run;
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst std::vector<MostVisitedHandler::MostVisitedPage>&
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MostVisitedHandler::GetPrePopulatedPages() {
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(arv): This needs to get the data from some configurable place.
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // http://crbug.com/17630
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static std::vector<MostVisitedPage> pages;
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (pages.empty()) {
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MostVisitedPage welcome_page = {
3363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        l10n_util::GetStringUTF16(IDS_NEW_TAB_CHROME_WELCOME_PAGE_TITLE),
3373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        GURL(l10n_util::GetStringUTF8(IDS_CHROME_WELCOME_URL)),
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        GURL("chrome://theme/IDR_NEWTAB_CHROME_WELCOME_PAGE_THUMBNAIL"),
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        GURL("chrome://theme/IDR_NEWTAB_CHROME_WELCOME_PAGE_FAVICON")};
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    pages.push_back(welcome_page);
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MostVisitedPage gallery_page = {
3433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        l10n_util::GetStringUTF16(IDS_NEW_TAB_THEMES_GALLERY_PAGE_TITLE),
3443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        GURL(l10n_util::GetStringUTF8(IDS_THEMES_GALLERY_URL)),
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        GURL("chrome://theme/IDR_NEWTAB_THEMES_GALLERY_THUMBNAIL"),
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        GURL("chrome://theme/IDR_NEWTAB_THEMES_GALLERY_FAVICON")};
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    pages.push_back(gallery_page);
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return pages;
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid MostVisitedHandler::Observe(NotificationType type,
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 const NotificationSource& source,
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 const NotificationDetails& details) {
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (type != NotificationType::HISTORY_URLS_DELETED) {
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Some URLs were deleted from history.  Reload the most visited list.
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  HandleGetMostVisited(NULL);
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid MostVisitedHandler::BlacklistURL(const GURL& url) {
36672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  history::TopSites* ts = web_ui_->GetProfile()->GetTopSites();
36772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (ts)
36872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ts->AddBlacklistedURL(url);
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstd::string MostVisitedHandler::GetDictionaryKeyForURL(const std::string& url) {
3723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return MD5String(url);
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid MostVisitedHandler::RegisterUserPrefs(PrefService* prefs) {
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  prefs->RegisterDictionaryPref(prefs::kNTPMostVisitedURLsBlacklist);
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  prefs->RegisterDictionaryPref(prefs::kNTPMostVisitedPinnedURLs);
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
380201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
381201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// static
382201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochstd::vector<GURL> MostVisitedHandler::GetPrePopulatedUrls() {
383201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  const std::vector<MostVisitedPage> pages =
384201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      MostVisitedHandler::GetPrePopulatedPages();
385201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  std::vector<GURL> page_urls;
386201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  for (size_t i = 0; i < pages.size(); ++i)
387201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    page_urls.push_back(pages[i].url);
388201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  return page_urls;
389201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
390