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.
5 #include "chrome/browser/bookmarks/chrome_bookmark_client.h"
8 #include "base/bind_helpers.h"
9 #include "base/logging.h"
10 #include "base/values.h"
11 #include "chrome/browser/favicon/favicon_service_factory.h"
12 #include "chrome/browser/policy/profile_policy_connector.h"
13 #include "chrome/browser/policy/profile_policy_connector_factory.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "components/bookmarks/browser/bookmark_model.h"
16 #include "components/bookmarks/browser/bookmark_node.h"
17 #include "components/bookmarks/browser/bookmark_utils.h"
18 #include "components/bookmarks/managed/managed_bookmarks_tracker.h"
19 #include "components/favicon/core/favicon_service.h"
20 #include "components/history/core/browser/history_service.h"
21 #include "components/history/core/browser/url_database.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/notification_details.h"
24 #include "content/public/browser/notification_source.h"
25 #include "content/public/browser/user_metrics.h"
26 #include "grit/components_strings.h"
27 #include "policy/policy_constants.h"
28 #include "ui/base/l10n/l10n_util.h"
30 using bookmarks::BookmarkModel
;
31 using bookmarks::BookmarkNode
;
32 using bookmarks::BookmarkPermanentNode
;
33 using bookmarks::ManagedBookmarksTracker
;
37 void RunCallbackWithImage(
38 const favicon_base::FaviconImageCallback
& callback
,
39 const favicon_base::FaviconRawBitmapResult
& bitmap_result
) {
40 favicon_base::FaviconImageResult result
;
41 if (bitmap_result
.is_valid()) {
42 result
.image
= gfx::Image::CreateFrom1xPNGBytes(
43 bitmap_result
.bitmap_data
->front(), bitmap_result
.bitmap_data
->size());
44 result
.icon_url
= bitmap_result
.icon_url
;
51 void LoadInitialContents(BookmarkPermanentNode
* node
,
52 base::ListValue
* initial_bookmarks
,
53 int64
* next_node_id
) {
54 // Load the initial contents of the |node| now, and assign it an unused ID.
55 int64 id
= *next_node_id
;
57 *next_node_id
= ManagedBookmarksTracker::LoadInitial(
58 node
, initial_bookmarks
, id
+ 1);
59 node
->set_visible(!node
->empty());
64 ChromeBookmarkClient::ChromeBookmarkClient(Profile
* profile
)
66 history_service_(NULL
),
69 supervised_node_(NULL
) {
72 ChromeBookmarkClient::~ChromeBookmarkClient() {
75 void ChromeBookmarkClient::Init(BookmarkModel
* model
) {
79 model_
->AddObserver(this);
81 managed_bookmarks_tracker_
.reset(new ManagedBookmarksTracker(
85 base::Bind(&ChromeBookmarkClient::GetManagedBookmarksDomain
,
86 base::Unretained(this))));
87 supervised_bookmarks_tracker_
.reset(new ManagedBookmarksTracker(
91 base::Callback
<std::string()>()));
94 void ChromeBookmarkClient::Shutdown() {
95 favicon_changed_subscription_
.reset();
97 model_
->RemoveObserver(this);
100 BookmarkClient::Shutdown();
103 bool ChromeBookmarkClient::PreferTouchIcon() {
111 base::CancelableTaskTracker::TaskId
112 ChromeBookmarkClient::GetFaviconImageForPageURL(
113 const GURL
& page_url
,
114 favicon_base::IconType type
,
115 const favicon_base::FaviconImageCallback
& callback
,
116 base::CancelableTaskTracker
* tracker
) {
117 favicon::FaviconService
* favicon_service
=
118 FaviconServiceFactory::GetForProfile(profile_
,
119 ServiceAccessType::EXPLICIT_ACCESS
);
120 if (!favicon_service
)
121 return base::CancelableTaskTracker::kBadTaskId
;
122 if (type
== favicon_base::FAVICON
) {
123 return favicon_service
->GetFaviconImageForPageURL(
124 page_url
, callback
, tracker
);
126 return favicon_service
->GetRawFaviconForPageURL(
130 base::Bind(&RunCallbackWithImage
, callback
),
135 bool ChromeBookmarkClient::SupportsTypedCountForNodes() {
139 void ChromeBookmarkClient::GetTypedCountForNodes(
140 const NodeSet
& nodes
,
141 NodeTypedCountPairs
* node_typed_count_pairs
) {
142 history::URLDatabase
* url_db
=
143 history_service_
? history_service_
->InMemoryDatabase() : NULL
;
144 for (NodeSet::const_iterator i
= nodes
.begin(); i
!= nodes
.end(); ++i
) {
147 // If |url_db| is the InMemoryDatabase, it might not cache all URLRows, but
148 // it guarantees to contain those with |typed_count| > 0. Thus, if we cannot
149 // fetch the URLRow, it is safe to assume that its |typed_count| is 0.
151 if (url_db
&& url_db
->GetRowForURL((*i
)->url(), &url
))
152 typed_count
= url
.typed_count();
154 NodeTypedCountPair
pair(*i
, typed_count
);
155 node_typed_count_pairs
->push_back(pair
);
159 bool ChromeBookmarkClient::IsPermanentNodeVisible(
160 const BookmarkPermanentNode
* node
) {
161 DCHECK(node
->type() == BookmarkNode::BOOKMARK_BAR
||
162 node
->type() == BookmarkNode::OTHER_NODE
||
163 node
->type() == BookmarkNode::MOBILE
||
164 node
== managed_node_
||
165 node
== supervised_node_
);
166 if (node
== managed_node_
|| node
== supervised_node_
)
169 return node
->type() != BookmarkNode::MOBILE
;
171 return node
->type() == BookmarkNode::MOBILE
;
175 void ChromeBookmarkClient::RecordAction(const base::UserMetricsAction
& action
) {
176 content::RecordAction(action
);
179 bookmarks::LoadExtraCallback
ChromeBookmarkClient::GetLoadExtraNodesCallback() {
180 // Create the managed_node_ and supervised_node_ with a temporary ID of 0 now.
181 // They will be populated (and assigned proper IDs) in the LoadExtraNodes
183 // The ownership of managed_node_ and supervised_node_ is in limbo until
184 // LoadExtraNodes runs, so we leave them in the care of the closure meanwhile.
185 scoped_ptr
<BookmarkPermanentNode
> managed(new BookmarkPermanentNode(0));
186 managed_node_
= managed
.get();
187 scoped_ptr
<BookmarkPermanentNode
> supervised(new BookmarkPermanentNode(0));
188 supervised_node_
= supervised
.get();
191 &ChromeBookmarkClient::LoadExtraNodes
,
192 base::Passed(&managed
),
193 base::Passed(managed_bookmarks_tracker_
->GetInitialManagedBookmarks()),
194 base::Passed(&supervised
),
196 supervised_bookmarks_tracker_
->GetInitialManagedBookmarks()));
199 bool ChromeBookmarkClient::CanSetPermanentNodeTitle(
200 const BookmarkNode
* permanent_node
) {
201 // The |managed_node_| can have its title updated if the user signs in or
202 // out, since the name of the managed domain can appear in it.
203 // Also, both |managed_node_| and |supervised_node_| can have their title
204 // updated on locale changes (crbug.com/459448).
205 return (!bookmarks::IsDescendantOf(permanent_node
, managed_node_
) &&
206 !bookmarks::IsDescendantOf(permanent_node
, supervised_node_
)) ||
207 permanent_node
== managed_node_
||
208 permanent_node
== supervised_node_
;
211 bool ChromeBookmarkClient::CanSyncNode(const BookmarkNode
* node
) {
212 return !bookmarks::IsDescendantOf(node
, managed_node_
) &&
213 !bookmarks::IsDescendantOf(node
, supervised_node_
);
216 bool ChromeBookmarkClient::CanBeEditedByUser(const BookmarkNode
* node
) {
217 return !bookmarks::IsDescendantOf(node
, managed_node_
) &&
218 !bookmarks::IsDescendantOf(node
, supervised_node_
);
221 void ChromeBookmarkClient::SetHistoryService(
222 history::HistoryService
* history_service
) {
223 DCHECK(history_service
);
224 history_service_
= history_service
;
225 favicon_changed_subscription_
= history_service_
->AddFaviconChangedCallback(
226 base::Bind(&BookmarkModel::OnFaviconChanged
, base::Unretained(model_
)));
229 void ChromeBookmarkClient::BookmarkModelChanged() {
232 void ChromeBookmarkClient::BookmarkNodeRemoved(
233 BookmarkModel
* model
,
234 const BookmarkNode
* parent
,
236 const BookmarkNode
* node
,
237 const std::set
<GURL
>& removed_urls
) {
238 if (history_service_
)
239 history_service_
->URLsNoLongerBookmarked(removed_urls
);
242 void ChromeBookmarkClient::BookmarkAllUserNodesRemoved(
243 BookmarkModel
* model
,
244 const std::set
<GURL
>& removed_urls
) {
245 if (history_service_
)
246 history_service_
->URLsNoLongerBookmarked(removed_urls
);
249 void ChromeBookmarkClient::BookmarkModelLoaded(BookmarkModel
* model
,
250 bool ids_reassigned
) {
251 // Start tracking the managed and supervised bookmarks. This will detect any
252 // changes that may have occurred while the initial managed and supervised
253 // bookmarks were being loaded on the background.
254 managed_bookmarks_tracker_
->Init(managed_node_
);
255 supervised_bookmarks_tracker_
->Init(supervised_node_
);
259 bookmarks::BookmarkPermanentNodeList
ChromeBookmarkClient::LoadExtraNodes(
260 scoped_ptr
<BookmarkPermanentNode
> managed_node
,
261 scoped_ptr
<base::ListValue
> initial_managed_bookmarks
,
262 scoped_ptr
<BookmarkPermanentNode
> supervised_node
,
263 scoped_ptr
<base::ListValue
> initial_supervised_bookmarks
,
264 int64
* next_node_id
) {
266 managed_node
.get(), initial_managed_bookmarks
.get(), next_node_id
);
267 managed_node
->SetTitle(l10n_util::GetStringUTF16(
268 IDS_BOOKMARK_BAR_MANAGED_FOLDER_DEFAULT_NAME
));
271 supervised_node
.get(), initial_supervised_bookmarks
.get(), next_node_id
);
272 supervised_node
->SetTitle(l10n_util::GetStringUTF16(
273 IDS_BOOKMARK_BAR_SUPERVISED_FOLDER_DEFAULT_NAME
));
275 bookmarks::BookmarkPermanentNodeList extra_nodes
;
276 // Ownership of the managed and supervised nodes passed to the caller.
277 extra_nodes
.push_back(managed_node
.release());
278 extra_nodes
.push_back(supervised_node
.release());
280 return extra_nodes
.Pass();
283 std::string
ChromeBookmarkClient::GetManagedBookmarksDomain() {
284 policy::ProfilePolicyConnector
* connector
=
285 policy::ProfilePolicyConnectorFactory::GetForBrowserContext(profile_
);
286 if (connector
->IsPolicyFromCloudPolicy(policy::key::kManagedBookmarks
))
287 return connector
->GetManagementDomain();
288 return std::string();