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