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