chrome_bookmark_client.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
1// Copyright 2014 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/bookmarks/chrome_bookmark_client.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/logging.h"
10#include "base/values.h"
11#include "chrome/browser/chrome_notification_types.h"
12#include "chrome/browser/favicon/favicon_changed_details.h"
13#include "chrome/browser/favicon/favicon_service.h"
14#include "chrome/browser/favicon/favicon_service_factory.h"
15#include "chrome/browser/history/history_service.h"
16#include "chrome/browser/history/history_service_factory.h"
17#include "chrome/browser/history/url_database.h"
18#include "chrome/browser/policy/profile_policy_connector.h"
19#include "chrome/browser/policy/profile_policy_connector_factory.h"
20#include "chrome/browser/profiles/profile.h"
21#include "chrome/browser/profiles/startup_task_runner_service.h"
22#include "chrome/browser/profiles/startup_task_runner_service_factory.h"
23#include "components/bookmarks/browser/bookmark_model.h"
24#include "components/bookmarks/browser/bookmark_node.h"
25#include "content/public/browser/browser_thread.h"
26#include "content/public/browser/notification_details.h"
27#include "content/public/browser/notification_source.h"
28#include "content/public/browser/user_metrics.h"
29#include "grit/components_strings.h"
30#include "policy/policy_constants.h"
31#include "ui/base/l10n/l10n_util.h"
32
33namespace {
34
35void NotifyHistoryOfRemovedURLs(Profile* profile,
36                                const std::set<GURL>& removed_urls) {
37  HistoryService* history_service =
38      HistoryServiceFactory::GetForProfile(profile, Profile::EXPLICIT_ACCESS);
39  if (history_service)
40    history_service->URLsNoLongerBookmarked(removed_urls);
41}
42
43}  // namespace
44
45ChromeBookmarkClient::ChromeBookmarkClient(Profile* profile)
46    : profile_(profile), model_(NULL), managed_node_(NULL) {
47}
48
49ChromeBookmarkClient::~ChromeBookmarkClient() {
50}
51
52void ChromeBookmarkClient::Init(BookmarkModel* model) {
53  DCHECK(model);
54  DCHECK(!model_);
55  model_ = model;
56  model_->AddObserver(this);
57
58  managed_bookmarks_tracker_.reset(new policy::ManagedBookmarksTracker(
59      model_,
60      profile_->GetPrefs(),
61      base::Bind(&ChromeBookmarkClient::GetManagedBookmarksDomain,
62                 base::Unretained(this))));
63
64  // Listen for changes to favicons so that we can update the favicon of the
65  // node appropriately.
66  registrar_.Add(this,
67                 chrome::NOTIFICATION_FAVICON_CHANGED,
68                 content::Source<Profile>(profile_));
69}
70
71void ChromeBookmarkClient::Shutdown() {
72  if (model_) {
73    registrar_.RemoveAll();
74
75    model_->RemoveObserver(this);
76    model_ = NULL;
77  }
78  BookmarkClient::Shutdown();
79}
80
81bool ChromeBookmarkClient::IsDescendantOfManagedNode(const BookmarkNode* node) {
82  return node && node->HasAncestor(managed_node_);
83}
84
85bool ChromeBookmarkClient::HasDescendantsOfManagedNode(
86    const std::vector<const BookmarkNode*>& list) {
87  for (size_t i = 0; i < list.size(); ++i) {
88    if (IsDescendantOfManagedNode(list[i]))
89      return true;
90  }
91  return false;
92}
93
94bool ChromeBookmarkClient::PreferTouchIcon() {
95#if !defined(OS_IOS)
96  return false;
97#else
98  return true;
99#endif
100}
101
102base::CancelableTaskTracker::TaskId ChromeBookmarkClient::GetFaviconImageForURL(
103    const GURL& page_url,
104    int icon_types,
105    int desired_size_in_dip,
106    const favicon_base::FaviconImageCallback& callback,
107    base::CancelableTaskTracker* tracker) {
108  FaviconService* favicon_service =
109      FaviconServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS);
110  if (!favicon_service)
111    return base::CancelableTaskTracker::kBadTaskId;
112  return favicon_service->GetFaviconImageForPageURL(
113      FaviconService::FaviconForPageURLParams(
114          page_url, icon_types, desired_size_in_dip),
115      callback,
116      tracker);
117}
118
119bool ChromeBookmarkClient::SupportsTypedCountForNodes() {
120  return true;
121}
122
123void ChromeBookmarkClient::GetTypedCountForNodes(
124    const NodeSet& nodes,
125    NodeTypedCountPairs* node_typed_count_pairs) {
126  HistoryService* history_service =
127      HistoryServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS);
128  history::URLDatabase* url_db =
129      history_service ? history_service->InMemoryDatabase() : NULL;
130  for (NodeSet::const_iterator i = nodes.begin(); i != nodes.end(); ++i) {
131    int typed_count = 0;
132
133    // If |url_db| is the InMemoryDatabase, it might not cache all URLRows, but
134    // it guarantees to contain those with |typed_count| > 0. Thus, if we cannot
135    // fetch the URLRow, it is safe to assume that its |typed_count| is 0.
136    history::URLRow url;
137    if (url_db && url_db->GetRowForURL((*i)->url(), &url))
138      typed_count = url.typed_count();
139
140    NodeTypedCountPair pair(*i, typed_count);
141    node_typed_count_pairs->push_back(pair);
142  }
143}
144
145bool ChromeBookmarkClient::IsPermanentNodeVisible(
146    const BookmarkPermanentNode* node) {
147  DCHECK(node->type() == BookmarkNode::BOOKMARK_BAR ||
148         node->type() == BookmarkNode::OTHER_NODE ||
149         node->type() == BookmarkNode::MOBILE ||
150         node == managed_node_);
151  if (node == managed_node_)
152    return false;
153#if !defined(OS_IOS)
154  return node->type() != BookmarkNode::MOBILE;
155#else
156  return node->type() == BookmarkNode::MOBILE;
157#endif
158}
159
160void ChromeBookmarkClient::RecordAction(const base::UserMetricsAction& action) {
161  content::RecordAction(action);
162}
163
164bookmarks::LoadExtraCallback ChromeBookmarkClient::GetLoadExtraNodesCallback() {
165  // Create the managed_node now; it will be populated in the LoadExtraNodes
166  // callback.
167  managed_node_ = new BookmarkPermanentNode(0);
168  return base::Bind(
169      &ChromeBookmarkClient::LoadExtraNodes,
170      StartupTaskRunnerServiceFactory::GetForProfile(profile_)
171          ->GetBookmarkTaskRunner(),
172      managed_node_,
173      base::Passed(managed_bookmarks_tracker_->GetInitialManagedBookmarks()));
174}
175
176bool ChromeBookmarkClient::CanSetPermanentNodeTitle(
177    const BookmarkNode* permanent_node) {
178  // The |managed_node_| can have its title updated if the user signs in or
179  // out.
180  return !IsDescendantOfManagedNode(permanent_node) ||
181         permanent_node == managed_node_;
182}
183
184bool ChromeBookmarkClient::CanSyncNode(const BookmarkNode* node) {
185  return !IsDescendantOfManagedNode(node);
186}
187
188bool ChromeBookmarkClient::CanBeEditedByUser(const BookmarkNode* node) {
189  return !IsDescendantOfManagedNode(node);
190}
191
192void ChromeBookmarkClient::Observe(
193    int type,
194    const content::NotificationSource& source,
195    const content::NotificationDetails& details) {
196  switch (type) {
197    case chrome::NOTIFICATION_FAVICON_CHANGED: {
198      content::Details<FaviconChangedDetails> favicon_details(details);
199      model_->OnFaviconChanged(favicon_details->urls);
200      break;
201    }
202
203    default:
204      NOTREACHED();
205      break;
206  }
207}
208
209void ChromeBookmarkClient::BookmarkModelChanged() {
210}
211
212void ChromeBookmarkClient::BookmarkNodeRemoved(
213    BookmarkModel* model,
214    const BookmarkNode* parent,
215    int old_index,
216    const BookmarkNode* node,
217    const std::set<GURL>& removed_urls) {
218  NotifyHistoryOfRemovedURLs(profile_, removed_urls);
219}
220
221void ChromeBookmarkClient::BookmarkAllUserNodesRemoved(
222    BookmarkModel* model,
223    const std::set<GURL>& removed_urls) {
224  NotifyHistoryOfRemovedURLs(profile_, removed_urls);
225}
226
227void ChromeBookmarkClient::BookmarkModelLoaded(BookmarkModel* model,
228                                               bool ids_reassigned) {
229  // Start tracking the managed bookmarks. This will detect any changes that
230  // may have occurred while the initial managed bookmarks were being loaded
231  // on the background.
232  managed_bookmarks_tracker_->Init(managed_node_);
233}
234
235// static
236bookmarks::BookmarkPermanentNodeList ChromeBookmarkClient::LoadExtraNodes(
237    const scoped_refptr<base::DeferredSequencedTaskRunner>& profile_io_runner,
238    BookmarkPermanentNode* managed_node,
239    scoped_ptr<base::ListValue> initial_managed_bookmarks,
240    int64* next_node_id) {
241  DCHECK(profile_io_runner->RunsTasksOnCurrentThread());
242  // Load the initial contents of the |managed_node| now, and assign it an
243  // unused ID.
244  int64 managed_id = *next_node_id;
245  managed_node->set_id(managed_id);
246  *next_node_id = policy::ManagedBookmarksTracker::LoadInitial(
247      managed_node, initial_managed_bookmarks.get(), managed_id + 1);
248  managed_node->set_visible(!managed_node->empty());
249  managed_node->SetTitle(
250      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_MANAGED_FOLDER_DEFAULT_NAME));
251
252  bookmarks::BookmarkPermanentNodeList extra_nodes;
253  extra_nodes.push_back(managed_node);
254  return extra_nodes.Pass();
255}
256
257std::string ChromeBookmarkClient::GetManagedBookmarksDomain() {
258  policy::ProfilePolicyConnector* connector =
259      policy::ProfilePolicyConnectorFactory::GetForProfile(profile_);
260  if (connector->IsPolicyFromCloudPolicy(policy::key::kManagedBookmarks))
261    return connector->GetManagementDomain();
262  return std::string();
263}
264