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.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/bookmarks/browser/bookmark_utils.h"
20 #include "components/history/core/browser/url_database.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/notification_details.h"
23 #include "content/public/browser/notification_source.h"
24 #include "content/public/browser/user_metrics.h"
25 #include "grit/components_strings.h"
26 #include "policy/policy_constants.h"
27 #include "ui/base/l10n/l10n_util.h"
29 using bookmarks::BookmarkModel
;
30 using bookmarks::BookmarkNode
;
31 using bookmarks::BookmarkPermanentNode
;
35 void RunCallbackWithImage(
36 const favicon_base::FaviconImageCallback
& callback
,
37 const favicon_base::FaviconRawBitmapResult
& bitmap_result
) {
38 favicon_base::FaviconImageResult result
;
39 if (bitmap_result
.is_valid()) {
40 result
.image
= gfx::Image::CreateFrom1xPNGBytes(
41 bitmap_result
.bitmap_data
->front(), bitmap_result
.bitmap_data
->size());
42 result
.icon_url
= bitmap_result
.icon_url
;
49 void LoadInitialContents(BookmarkPermanentNode
* node
,
50 base::ListValue
* initial_bookmarks
,
51 int64
* next_node_id
) {
52 // Load the initial contents of the |node| now, and assign it an unused ID.
53 int64 id
= *next_node_id
;
55 *next_node_id
= policy::ManagedBookmarksTracker::LoadInitial(
56 node
, initial_bookmarks
, id
+ 1);
57 node
->set_visible(!node
->empty());
62 ChromeBookmarkClient::ChromeBookmarkClient(Profile
* profile
)
64 history_service_(NULL
),
67 supervised_node_(NULL
) {
70 ChromeBookmarkClient::~ChromeBookmarkClient() {
73 void ChromeBookmarkClient::Init(BookmarkModel
* model
) {
77 model_
->AddObserver(this);
79 managed_bookmarks_tracker_
.reset(new policy::ManagedBookmarksTracker(
83 base::Bind(&ChromeBookmarkClient::GetManagedBookmarksDomain
,
84 base::Unretained(this))));
85 supervised_bookmarks_tracker_
.reset(new policy::ManagedBookmarksTracker(
89 base::Callback
<std::string()>()));
92 void ChromeBookmarkClient::Shutdown() {
93 favicon_changed_subscription_
.reset();
95 model_
->RemoveObserver(this);
98 BookmarkClient::Shutdown();
101 bool ChromeBookmarkClient::PreferTouchIcon() {
109 base::CancelableTaskTracker::TaskId
110 ChromeBookmarkClient::GetFaviconImageForPageURL(
111 const GURL
& page_url
,
112 favicon_base::IconType type
,
113 const favicon_base::FaviconImageCallback
& callback
,
114 base::CancelableTaskTracker
* tracker
) {
115 FaviconService
* favicon_service
= FaviconServiceFactory::GetForProfile(
116 profile_
, ServiceAccessType::EXPLICIT_ACCESS
);
117 if (!favicon_service
)
118 return base::CancelableTaskTracker::kBadTaskId
;
119 if (type
== favicon_base::FAVICON
) {
120 return favicon_service
->GetFaviconImageForPageURL(
121 page_url
, callback
, tracker
);
123 return favicon_service
->GetRawFaviconForPageURL(
127 base::Bind(&RunCallbackWithImage
, callback
),
132 bool ChromeBookmarkClient::SupportsTypedCountForNodes() {
136 void ChromeBookmarkClient::GetTypedCountForNodes(
137 const NodeSet
& nodes
,
138 NodeTypedCountPairs
* node_typed_count_pairs
) {
139 history::URLDatabase
* url_db
=
140 history_service_
? history_service_
->InMemoryDatabase() : NULL
;
141 for (NodeSet::const_iterator i
= nodes
.begin(); i
!= nodes
.end(); ++i
) {
144 // If |url_db| is the InMemoryDatabase, it might not cache all URLRows, but
145 // it guarantees to contain those with |typed_count| > 0. Thus, if we cannot
146 // fetch the URLRow, it is safe to assume that its |typed_count| is 0.
148 if (url_db
&& url_db
->GetRowForURL((*i
)->url(), &url
))
149 typed_count
= url
.typed_count();
151 NodeTypedCountPair
pair(*i
, typed_count
);
152 node_typed_count_pairs
->push_back(pair
);
156 bool ChromeBookmarkClient::IsPermanentNodeVisible(
157 const BookmarkPermanentNode
* node
) {
158 DCHECK(node
->type() == BookmarkNode::BOOKMARK_BAR
||
159 node
->type() == BookmarkNode::OTHER_NODE
||
160 node
->type() == BookmarkNode::MOBILE
||
161 node
== managed_node_
||
162 node
== supervised_node_
);
163 if (node
== managed_node_
|| node
== supervised_node_
)
166 return node
->type() != BookmarkNode::MOBILE
;
168 return node
->type() == BookmarkNode::MOBILE
;
172 void ChromeBookmarkClient::RecordAction(const base::UserMetricsAction
& action
) {
173 content::RecordAction(action
);
176 bookmarks::LoadExtraCallback
ChromeBookmarkClient::GetLoadExtraNodesCallback() {
177 // Create the managed_node_ and supervised_node_ with a temporary ID of 0 now.
178 // They will be populated (and assigned proper IDs) in the LoadExtraNodes
180 // The ownership of managed_node_ and supervised_node_ is in limbo until
181 // LoadExtraNodes runs, so we leave them in the care of the closure meanwhile.
182 scoped_ptr
<BookmarkPermanentNode
> managed(new BookmarkPermanentNode(0));
183 managed_node_
= managed
.get();
184 scoped_ptr
<BookmarkPermanentNode
> supervised(new BookmarkPermanentNode(0));
185 supervised_node_
= supervised
.get();
188 &ChromeBookmarkClient::LoadExtraNodes
,
189 base::Passed(&managed
),
190 base::Passed(managed_bookmarks_tracker_
->GetInitialManagedBookmarks()),
191 base::Passed(&supervised
),
193 supervised_bookmarks_tracker_
->GetInitialManagedBookmarks()));
196 bool ChromeBookmarkClient::CanSetPermanentNodeTitle(
197 const BookmarkNode
* permanent_node
) {
198 // The |managed_node_| can have its title updated if the user signs in or
199 // out, since the name of the managed domain can appear in it. The
200 // |supervised_node_| has a fixed title which can never be updated.
201 return (!bookmarks::IsDescendantOf(permanent_node
, managed_node_
) &&
202 !bookmarks::IsDescendantOf(permanent_node
, supervised_node_
)) ||
203 permanent_node
== managed_node_
;
206 bool ChromeBookmarkClient::CanSyncNode(const BookmarkNode
* node
) {
207 return !bookmarks::IsDescendantOf(node
, managed_node_
) &&
208 !bookmarks::IsDescendantOf(node
, supervised_node_
);
211 bool ChromeBookmarkClient::CanBeEditedByUser(const BookmarkNode
* node
) {
212 return !bookmarks::IsDescendantOf(node
, managed_node_
) &&
213 !bookmarks::IsDescendantOf(node
, supervised_node_
);
216 void ChromeBookmarkClient::SetHistoryService(HistoryService
* history_service
) {
217 DCHECK(history_service
);
218 history_service_
= history_service
;
219 favicon_changed_subscription_
= history_service_
->AddFaviconChangedCallback(
220 base::Bind(&BookmarkModel::OnFaviconChanged
, base::Unretained(model_
)));
223 void ChromeBookmarkClient::BookmarkModelChanged() {
226 void ChromeBookmarkClient::BookmarkNodeRemoved(
227 BookmarkModel
* model
,
228 const BookmarkNode
* parent
,
230 const BookmarkNode
* node
,
231 const std::set
<GURL
>& removed_urls
) {
232 if (history_service_
)
233 history_service_
->URLsNoLongerBookmarked(removed_urls
);
236 void ChromeBookmarkClient::BookmarkAllUserNodesRemoved(
237 BookmarkModel
* model
,
238 const std::set
<GURL
>& removed_urls
) {
239 if (history_service_
)
240 history_service_
->URLsNoLongerBookmarked(removed_urls
);
243 void ChromeBookmarkClient::BookmarkModelLoaded(BookmarkModel
* model
,
244 bool ids_reassigned
) {
245 // Start tracking the managed and supervised bookmarks. This will detect any
246 // changes that may have occurred while the initial managed and supervised
247 // bookmarks were being loaded on the background.
248 managed_bookmarks_tracker_
->Init(managed_node_
);
249 supervised_bookmarks_tracker_
->Init(supervised_node_
);
253 bookmarks::BookmarkPermanentNodeList
ChromeBookmarkClient::LoadExtraNodes(
254 scoped_ptr
<BookmarkPermanentNode
> managed_node
,
255 scoped_ptr
<base::ListValue
> initial_managed_bookmarks
,
256 scoped_ptr
<BookmarkPermanentNode
> supervised_node
,
257 scoped_ptr
<base::ListValue
> initial_supervised_bookmarks
,
258 int64
* next_node_id
) {
260 managed_node
.get(), initial_managed_bookmarks
.get(), next_node_id
);
261 managed_node
->SetTitle(l10n_util::GetStringUTF16(
262 IDS_BOOKMARK_BAR_MANAGED_FOLDER_DEFAULT_NAME
));
265 supervised_node
.get(), initial_supervised_bookmarks
.get(), next_node_id
);
266 supervised_node
->SetTitle(l10n_util::GetStringUTF16(
267 IDS_BOOKMARK_BAR_SUPERVISED_FOLDER_DEFAULT_NAME
));
269 bookmarks::BookmarkPermanentNodeList extra_nodes
;
270 // Ownership of the managed and supervised nodes passed to the caller.
271 extra_nodes
.push_back(managed_node
.release());
272 extra_nodes
.push_back(supervised_node
.release());
274 return extra_nodes
.Pass();
277 std::string
ChromeBookmarkClient::GetManagedBookmarksDomain() {
278 policy::ProfilePolicyConnector
* connector
=
279 policy::ProfilePolicyConnectorFactory::GetForBrowserContext(profile_
);
280 if (connector
->IsPolicyFromCloudPolicy(policy::key::kManagedBookmarks
))
281 return connector
->GetManagementDomain();
282 return std::string();