1 // Copyright (c) 2012 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/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h"
9 #include "base/memory/linked_ptr.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "chrome/browser/bookmarks/bookmark_model.h"
15 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
16 #include "chrome/browser/bookmarks/bookmark_node_data.h"
17 #include "chrome/browser/bookmarks/bookmark_stats.h"
18 #include "chrome/browser/bookmarks/bookmark_utils.h"
19 #include "chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_constants.h"
20 #include "chrome/browser/extensions/api/bookmarks/bookmark_api_constants.h"
21 #include "chrome/browser/extensions/api/bookmarks/bookmark_api_helpers.h"
22 #include "chrome/browser/extensions/extension_function_dispatcher.h"
23 #include "chrome/browser/extensions/extension_web_ui.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/browser/ui/bookmarks/bookmark_drag_drop.h"
26 #include "chrome/browser/undo/bookmark_undo_service.h"
27 #include "chrome/browser/undo/bookmark_undo_service_factory.h"
28 #include "chrome/browser/undo/bookmark_undo_utils.h"
29 #include "chrome/common/extensions/api/bookmark_manager_private.h"
30 #include "chrome/common/pref_names.h"
31 #include "components/user_prefs/user_prefs.h"
32 #include "content/public/browser/render_view_host.h"
33 #include "content/public/browser/web_contents.h"
34 #include "content/public/browser/web_contents_view.h"
35 #include "content/public/browser/web_ui.h"
36 #include "extensions/browser/event_router.h"
37 #include "extensions/browser/extension_system.h"
38 #include "extensions/browser/view_type_utils.h"
39 #include "grit/generated_resources.h"
40 #include "ui/base/dragdrop/drag_drop_types.h"
41 #include "ui/base/l10n/l10n_util.h"
42 #include "ui/base/webui/web_ui_util.h"
45 #include "win8/util/win8_util.h"
48 namespace extensions {
50 namespace bookmark_keys = bookmark_api_constants;
51 namespace bookmark_manager_private = api::bookmark_manager_private;
52 namespace CanPaste = api::bookmark_manager_private::CanPaste;
53 namespace Copy = api::bookmark_manager_private::Copy;
54 namespace Cut = api::bookmark_manager_private::Cut;
55 namespace Drop = api::bookmark_manager_private::Drop;
56 namespace GetSubtree = api::bookmark_manager_private::GetSubtree;
57 namespace manager_keys = bookmark_manager_api_constants;
58 namespace GetMetaInfo = api::bookmark_manager_private::GetMetaInfo;
59 namespace Paste = api::bookmark_manager_private::Paste;
60 namespace RedoInfo = api::bookmark_manager_private::GetRedoInfo;
61 namespace RemoveTrees = api::bookmark_manager_private::RemoveTrees;
62 namespace SetMetaInfo = api::bookmark_manager_private::SetMetaInfo;
63 namespace SortChildren = api::bookmark_manager_private::SortChildren;
64 namespace StartDrag = api::bookmark_manager_private::StartDrag;
65 namespace UndoInfo = api::bookmark_manager_private::GetUndoInfo;
67 using content::WebContents;
71 // Returns a single bookmark node from the argument ID.
72 // This returns NULL in case of failure.
73 const BookmarkNode* GetNodeFromString(
74 BookmarkModel* model, const std::string& id_string) {
76 if (!base::StringToInt64(id_string, &id))
78 return model->GetNodeByID(id);
81 // Gets a vector of bookmark nodes from the argument list of IDs.
82 // This returns false in the case of failure.
83 bool GetNodesFromVector(BookmarkModel* model,
84 const std::vector<std::string>& id_strings,
85 std::vector<const BookmarkNode*>* nodes) {
87 if (id_strings.empty())
90 for (size_t i = 0; i < id_strings.size(); ++i) {
91 const BookmarkNode* node = GetNodeFromString(model, id_strings[i]);
94 nodes->push_back(node);
100 // Recursively adds a node to a list. This is by used |BookmarkNodeDataToJSON|
101 // when the data comes from the current profile. In this case we have a
102 // BookmarkNode since we got the data from the current profile.
103 void AddNodeToList(base::ListValue* list, const BookmarkNode& node) {
104 base::DictionaryValue* dict = new base::DictionaryValue();
106 // Add id and parentId so we can associate the data with existing nodes on the
108 std::string id_string = base::Int64ToString(node.id());
109 dict->SetString(bookmark_keys::kIdKey, id_string);
111 std::string parent_id_string = base::Int64ToString(node.parent()->id());
112 dict->SetString(bookmark_keys::kParentIdKey, parent_id_string);
115 dict->SetString(bookmark_keys::kUrlKey, node.url().spec());
117 dict->SetString(bookmark_keys::kTitleKey, node.GetTitle());
119 base::ListValue* children = new base::ListValue();
120 for (int i = 0; i < node.child_count(); ++i)
121 AddNodeToList(children, *node.GetChild(i));
122 dict->Set(bookmark_keys::kChildrenKey, children);
127 // Recursively adds an element to a list. This is used by
128 // |BookmarkNodeDataToJSON| when the data comes from a different profile. When
129 // the data comes from a different profile we do not have any IDs or parent IDs.
130 void AddElementToList(base::ListValue* list,
131 const BookmarkNodeData::Element& element) {
132 base::DictionaryValue* dict = new base::DictionaryValue();
135 dict->SetString(bookmark_keys::kUrlKey, element.url.spec());
137 dict->SetString(bookmark_keys::kTitleKey, element.title);
139 base::ListValue* children = new base::ListValue();
140 for (size_t i = 0; i < element.children.size(); ++i)
141 AddElementToList(children, element.children[i]);
142 dict->Set(bookmark_keys::kChildrenKey, children);
147 // Builds the JSON structure based on the BookmarksDragData.
148 void BookmarkNodeDataToJSON(Profile* profile, const BookmarkNodeData& data,
149 base::ListValue* args) {
150 bool same_profile = data.IsFromProfile(profile);
151 base::DictionaryValue* value = new base::DictionaryValue();
152 value->SetBoolean(manager_keys::kSameProfileKey, same_profile);
154 base::ListValue* list = new base::ListValue();
156 std::vector<const BookmarkNode*> nodes = data.GetNodes(profile);
157 for (size_t i = 0; i < nodes.size(); ++i)
158 AddNodeToList(list, *nodes[i]);
160 // We do not have an node IDs when the data comes from a different profile.
161 std::vector<BookmarkNodeData::Element> elements = data.elements;
162 for (size_t i = 0; i < elements.size(); ++i)
163 AddElementToList(list, elements[i]);
165 value->Set(manager_keys::kElementsKey, list);
172 BookmarkManagerPrivateEventRouter::BookmarkManagerPrivateEventRouter(
174 content::WebContents* web_contents)
176 web_contents_(web_contents) {
177 BookmarkTabHelper* bookmark_tab_helper =
178 BookmarkTabHelper::FromWebContents(web_contents_);
179 bookmark_tab_helper->set_bookmark_drag_delegate(this);
182 BookmarkManagerPrivateEventRouter::~BookmarkManagerPrivateEventRouter() {
183 BookmarkTabHelper* bookmark_tab_helper =
184 BookmarkTabHelper::FromWebContents(web_contents_);
185 if (bookmark_tab_helper->bookmark_drag_delegate() == this)
186 bookmark_tab_helper->set_bookmark_drag_delegate(NULL);
189 void BookmarkManagerPrivateEventRouter::DispatchEvent(
190 const std::string& event_name,
191 scoped_ptr<base::ListValue> args) {
192 if (!ExtensionSystem::Get(profile_)->event_router())
195 scoped_ptr<Event> event(new Event(event_name, args.Pass()));
196 ExtensionSystem::Get(profile_)->event_router()->BroadcastEvent(event.Pass());
199 void BookmarkManagerPrivateEventRouter::DispatchDragEvent(
200 const BookmarkNodeData& data,
201 const std::string& event_name) {
202 if (data.size() == 0)
205 scoped_ptr<base::ListValue> args(new base::ListValue());
206 BookmarkNodeDataToJSON(profile_, data, args.get());
207 DispatchEvent(event_name, args.Pass());
210 void BookmarkManagerPrivateEventRouter::OnDragEnter(
211 const BookmarkNodeData& data) {
212 DispatchDragEvent(data, bookmark_manager_private::OnDragEnter::kEventName);
215 void BookmarkManagerPrivateEventRouter::OnDragOver(
216 const BookmarkNodeData& data) {
217 // Intentionally empty since these events happens too often and floods the
218 // message queue. We do not need this event for the bookmark manager anyway.
221 void BookmarkManagerPrivateEventRouter::OnDragLeave(
222 const BookmarkNodeData& data) {
223 DispatchDragEvent(data, bookmark_manager_private::OnDragLeave::kEventName);
226 void BookmarkManagerPrivateEventRouter::OnDrop(const BookmarkNodeData& data) {
227 DispatchDragEvent(data, bookmark_manager_private::OnDrop::kEventName);
229 // Make a copy that is owned by this instance.
230 ClearBookmarkNodeData();
231 bookmark_drag_data_ = data;
234 const BookmarkNodeData*
235 BookmarkManagerPrivateEventRouter::GetBookmarkNodeData() {
236 if (bookmark_drag_data_.is_valid())
237 return &bookmark_drag_data_;
241 void BookmarkManagerPrivateEventRouter::ClearBookmarkNodeData() {
242 bookmark_drag_data_.Clear();
245 bool ClipboardBookmarkManagerFunction::CopyOrCut(bool cut,
246 const std::vector<std::string>& id_list) {
247 BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
248 std::vector<const BookmarkNode*> nodes;
249 EXTENSION_FUNCTION_VALIDATE(GetNodesFromVector(model, id_list, &nodes));
250 bookmark_utils::CopyToClipboard(model, nodes, cut);
254 bool BookmarkManagerPrivateCopyFunction::RunImpl() {
255 scoped_ptr<Copy::Params> params(Copy::Params::Create(*args_));
256 EXTENSION_FUNCTION_VALIDATE(params);
257 return CopyOrCut(false, params->id_list);
260 bool BookmarkManagerPrivateCutFunction::RunImpl() {
261 if (!EditBookmarksEnabled())
264 scoped_ptr<Cut::Params> params(Cut::Params::Create(*args_));
265 EXTENSION_FUNCTION_VALIDATE(params);
266 return CopyOrCut(true, params->id_list);
269 bool BookmarkManagerPrivatePasteFunction::RunImpl() {
270 if (!EditBookmarksEnabled())
273 scoped_ptr<Paste::Params> params(Paste::Params::Create(*args_));
274 EXTENSION_FUNCTION_VALIDATE(params);
275 BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
276 const BookmarkNode* parent_node = GetNodeFromString(model, params->parent_id);
278 error_ = bookmark_keys::kNoParentError;
281 bool can_paste = bookmark_utils::CanPasteFromClipboard(parent_node);
285 // We want to use the highest index of the selected nodes as a destination.
286 std::vector<const BookmarkNode*> nodes;
287 // No need to test return value, if we got an empty list, we insert at end.
288 if (params->selected_id_list)
289 GetNodesFromVector(model, *params->selected_id_list, &nodes);
290 int highest_index = -1; // -1 means insert at end of list.
291 for (size_t i = 0; i < nodes.size(); ++i) {
292 // + 1 so that we insert after the selection.
293 int index = parent_node->GetIndexOf(nodes[i]) + 1;
294 if (index > highest_index)
295 highest_index = index;
298 bookmark_utils::PasteFromClipboard(model, parent_node, highest_index);
302 bool BookmarkManagerPrivateCanPasteFunction::RunImpl() {
303 if (!EditBookmarksEnabled())
306 scoped_ptr<CanPaste::Params> params(CanPaste::Params::Create(*args_));
307 EXTENSION_FUNCTION_VALIDATE(params);
309 BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
310 const BookmarkNode* parent_node = GetNodeFromString(model, params->parent_id);
312 error_ = bookmark_keys::kNoParentError;
315 bool can_paste = bookmark_utils::CanPasteFromClipboard(parent_node);
316 SetResult(new base::FundamentalValue(can_paste));
320 bool BookmarkManagerPrivateSortChildrenFunction::RunImpl() {
321 if (!EditBookmarksEnabled())
324 scoped_ptr<SortChildren::Params> params(SortChildren::Params::Create(*args_));
325 EXTENSION_FUNCTION_VALIDATE(params);
327 BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
328 const BookmarkNode* parent_node = GetNodeFromString(model, params->parent_id);
330 error_ = bookmark_keys::kNoParentError;
333 model->SortChildren(parent_node);
337 bool BookmarkManagerPrivateGetStringsFunction::RunImpl() {
338 base::DictionaryValue* localized_strings = new base::DictionaryValue();
340 localized_strings->SetString("title",
341 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_TITLE));
342 localized_strings->SetString("search_button",
343 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SEARCH_BUTTON));
344 localized_strings->SetString("organize_menu",
345 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_ORGANIZE_MENU));
346 localized_strings->SetString("show_in_folder",
347 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SHOW_IN_FOLDER));
348 localized_strings->SetString("sort",
349 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SORT));
350 localized_strings->SetString("import_menu",
351 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_IMPORT_MENU));
352 localized_strings->SetString("export_menu",
353 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_EXPORT_MENU));
354 localized_strings->SetString("rename_folder",
355 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_RENAME_FOLDER));
356 localized_strings->SetString("edit",
357 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_EDIT));
358 localized_strings->SetString("should_open_all",
359 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_SHOULD_OPEN_ALL));
360 localized_strings->SetString("open_incognito",
361 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_INCOGNITO));
362 localized_strings->SetString("open_in_new_tab",
363 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_IN_NEW_TAB));
364 localized_strings->SetString("open_in_new_window",
365 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_IN_NEW_WINDOW));
366 localized_strings->SetString("add_new_bookmark",
367 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
368 localized_strings->SetString("new_folder",
369 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_NEW_FOLDER));
370 localized_strings->SetString("open_all",
371 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_ALL));
372 localized_strings->SetString("open_all_new_window",
373 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
374 localized_strings->SetString("open_all_incognito",
375 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
376 localized_strings->SetString("remove",
377 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_REMOVE));
378 localized_strings->SetString("copy",
379 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_COPY));
380 localized_strings->SetString("cut",
381 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_CUT));
382 localized_strings->SetString("paste",
383 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_PASTE));
384 localized_strings->SetString("delete",
385 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_DELETE));
386 localized_strings->SetString("undo_delete",
387 l10n_util::GetStringUTF16(IDS_UNDO_DELETE));
388 localized_strings->SetString("new_folder_name",
389 l10n_util::GetStringUTF16(IDS_BOOKMARK_EDITOR_NEW_FOLDER_NAME));
390 localized_strings->SetString("name_input_placeholder",
391 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_NAME_INPUT_PLACE_HOLDER));
392 localized_strings->SetString("url_input_placeholder",
393 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_URL_INPUT_PLACE_HOLDER));
394 localized_strings->SetString("invalid_url",
395 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_INVALID_URL));
396 localized_strings->SetString("recent",
397 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_RECENT));
398 localized_strings->SetString("search",
399 l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SEARCH));
400 localized_strings->SetString("save",
401 l10n_util::GetStringUTF16(IDS_SAVE));
402 localized_strings->SetString("cancel",
403 l10n_util::GetStringUTF16(IDS_CANCEL));
405 webui::SetFontAndTextDirection(localized_strings);
407 SetResult(localized_strings);
409 // This is needed because unlike the rest of these functions, this class
410 // inherits from AsyncFunction directly, rather than BookmarkFunction.
416 bool BookmarkManagerPrivateStartDragFunction::RunImpl() {
417 if (!EditBookmarksEnabled())
420 scoped_ptr<StartDrag::Params> params(StartDrag::Params::Create(*args_));
421 EXTENSION_FUNCTION_VALIDATE(params);
423 BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
424 std::vector<const BookmarkNode*> nodes;
425 EXTENSION_FUNCTION_VALIDATE(
426 GetNodesFromVector(model, params->id_list, &nodes));
428 WebContents* web_contents =
429 WebContents::FromRenderViewHost(render_view_host_);
430 if (GetViewType(web_contents) == VIEW_TYPE_TAB_CONTENTS) {
431 WebContents* web_contents =
432 dispatcher()->delegate()->GetAssociatedWebContents();
435 ui::DragDropTypes::DragEventSource source =
436 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE;
437 if (params->is_from_touch)
438 source = ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH;
440 chrome::DragBookmarks(
441 GetProfile(), nodes, web_contents->GetView()->GetNativeView(), source);
450 bool BookmarkManagerPrivateDropFunction::RunImpl() {
451 if (!EditBookmarksEnabled())
454 scoped_ptr<Drop::Params> params(Drop::Params::Create(*args_));
455 EXTENSION_FUNCTION_VALIDATE(params);
457 BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
459 const BookmarkNode* drop_parent = GetNodeFromString(model, params->parent_id);
461 error_ = bookmark_keys::kNoParentError;
467 drop_index = *params->index;
469 drop_index = drop_parent->child_count();
471 WebContents* web_contents =
472 WebContents::FromRenderViewHost(render_view_host_);
473 if (GetViewType(web_contents) == VIEW_TYPE_TAB_CONTENTS) {
474 WebContents* web_contents =
475 dispatcher()->delegate()->GetAssociatedWebContents();
477 ExtensionWebUI* web_ui =
478 static_cast<ExtensionWebUI*>(web_contents->GetWebUI()->GetController());
480 BookmarkManagerPrivateEventRouter* router =
481 web_ui->bookmark_manager_private_event_router();
484 const BookmarkNodeData* drag_data = router->GetBookmarkNodeData();
485 if (drag_data == NULL) {
486 NOTREACHED() <<"Somehow we're dropping null bookmark data";
489 chrome::DropBookmarks(GetProfile(), *drag_data, drop_parent, drop_index);
491 router->ClearBookmarkNodeData();
499 bool BookmarkManagerPrivateGetSubtreeFunction::RunImpl() {
500 scoped_ptr<GetSubtree::Params> params(GetSubtree::Params::Create(*args_));
501 EXTENSION_FUNCTION_VALIDATE(params);
503 const BookmarkNode* node = NULL;
505 if (params->id == "") {
506 BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
507 node = model->root_node();
509 node = GetBookmarkNodeFromId(params->id);
514 std::vector<linked_ptr<api::bookmarks::BookmarkTreeNode> > nodes;
515 if (params->folders_only)
516 bookmark_api_helpers::AddNodeFoldersOnly(node, &nodes, true);
518 bookmark_api_helpers::AddNode(node, &nodes, true);
519 results_ = GetSubtree::Results::Create(nodes);
523 bool BookmarkManagerPrivateCanEditFunction::RunImpl() {
524 PrefService* prefs = user_prefs::UserPrefs::Get(GetProfile());
525 SetResult(new base::FundamentalValue(
526 prefs->GetBoolean(prefs::kEditBookmarksEnabled)));
530 bool BookmarkManagerPrivateRecordLaunchFunction::RunImpl() {
531 RecordBookmarkLaunch(NULL, BOOKMARK_LAUNCH_LOCATION_MANAGER);
535 bool BookmarkManagerPrivateGetMetaInfoFunction::RunImpl() {
536 scoped_ptr<GetMetaInfo::Params> params(GetMetaInfo::Params::Create(*args_));
537 EXTENSION_FUNCTION_VALIDATE(params);
539 const BookmarkNode* node = GetBookmarkNodeFromId(params->id);
544 if (node->GetMetaInfo(params->key, &value))
545 results_ = GetMetaInfo::Results::Create(value);
549 bool BookmarkManagerPrivateSetMetaInfoFunction::RunImpl() {
550 scoped_ptr<SetMetaInfo::Params> params(SetMetaInfo::Params::Create(*args_));
551 EXTENSION_FUNCTION_VALIDATE(params);
553 const BookmarkNode* node = GetBookmarkNodeFromId(params->id);
557 BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
558 model->SetNodeMetaInfo(node, params->key, params->value);
562 bool BookmarkManagerPrivateCanOpenNewWindowsFunction::RunImpl() {
563 bool can_open_new_windows = true;
566 if (win8::IsSingleWindowMetroMode())
567 can_open_new_windows = false;
570 SetResult(new base::FundamentalValue(can_open_new_windows));
574 bool BookmarkManagerPrivateRemoveTreesFunction::RunImpl() {
575 scoped_ptr<RemoveTrees::Params> params(RemoveTrees::Params::Create(*args_));
576 EXTENSION_FUNCTION_VALIDATE(params);
578 #if !defined(OS_ANDROID)
579 ScopedGroupBookmarkActions group_deletes(GetProfile());
581 BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
583 for (size_t i = 0; i < params->id_list.size(); ++i) {
584 if (!GetBookmarkIdAsInt64(params->id_list[i], &id))
586 if (!bookmark_api_helpers::RemoveNode(model, id, true, &error_))
593 bool BookmarkManagerPrivateUndoFunction::RunImpl() {
594 #if !defined(OS_ANDROID)
595 BookmarkUndoServiceFactory::GetForProfile(GetProfile())->undo_manager()->
602 bool BookmarkManagerPrivateRedoFunction::RunImpl() {
603 #if !defined(OS_ANDROID)
604 BookmarkUndoServiceFactory::GetForProfile(GetProfile())->undo_manager()->
611 bool BookmarkManagerPrivateGetUndoInfoFunction::RunImpl() {
612 #if !defined(OS_ANDROID)
613 UndoManager* undo_manager =
614 BookmarkUndoServiceFactory::GetForProfile(GetProfile())->undo_manager();
616 UndoInfo::Results::Result result;
617 result.enabled = undo_manager->undo_count() > 0;
618 result.label = base::UTF16ToUTF8(undo_manager->GetUndoLabel());
620 results_ = UndoInfo::Results::Create(result);
621 #endif // !defined(OS_ANDROID)
626 bool BookmarkManagerPrivateGetRedoInfoFunction::RunImpl() {
627 #if !defined(OS_ANDROID)
628 UndoManager* undo_manager =
629 BookmarkUndoServiceFactory::GetForProfile(GetProfile())->undo_manager();
631 RedoInfo::Results::Result result;
632 result.enabled = undo_manager->redo_count() > 0;
633 result.label = base::UTF16ToUTF8(undo_manager->GetRedoLabel());
635 results_ = RedoInfo::Results::Create(result);
636 #endif // !defined(OS_ANDROID)
641 } // namespace extensions