1 // Copyright 2013 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/android/bookmarks/bookmarks_bridge.h"
7 #include "base/android/jni_array.h"
8 #include "base/android/jni_string.h"
9 #include "base/containers/stack_container.h"
10 #include "base/i18n/string_compare.h"
11 #include "base/prefs/pref_service.h"
12 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
13 #include "chrome/browser/bookmarks/enhanced_bookmarks_features.h"
14 #include "chrome/browser/bookmarks/managed_bookmark_service_factory.h"
15 #include "chrome/browser/profiles/incognito_helpers.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/profiles/profile_android.h"
18 #include "chrome/browser/signin/signin_manager_factory.h"
19 #include "chrome/browser/undo/bookmark_undo_service_factory.h"
20 #include "chrome/common/pref_names.h"
21 #include "components/bookmarks/browser/bookmark_match.h"
22 #include "components/bookmarks/browser/bookmark_model.h"
23 #include "components/bookmarks/browser/bookmark_utils.h"
24 #include "components/bookmarks/browser/scoped_group_bookmark_actions.h"
25 #include "components/bookmarks/common/android/bookmark_type.h"
26 #include "components/bookmarks/managed/managed_bookmark_service.h"
27 #include "components/query_parser/query_parser.h"
28 #include "components/signin/core/browser/signin_manager.h"
29 #include "components/undo/bookmark_undo_service.h"
30 #include "components/undo/undo_manager.h"
31 #include "content/public/browser/browser_thread.h"
32 #include "grit/components_strings.h"
33 #include "jni/BookmarksBridge_jni.h"
34 #include "ui/base/l10n/l10n_util.h"
36 using base::android::AttachCurrentThread
;
37 using base::android::ConvertUTF8ToJavaString
;
38 using base::android::ConvertUTF16ToJavaString
;
39 using base::android::ScopedJavaLocalRef
;
40 using base::android::ScopedJavaGlobalRef
;
41 using base::android::ToJavaIntArray
;
42 using bookmarks::android::JavaBookmarkIdCreateBookmarkId
;
43 using bookmarks::android::JavaBookmarkIdGetId
;
44 using bookmarks::android::JavaBookmarkIdGetType
;
45 using bookmarks::BookmarkModel
;
46 using bookmarks::BookmarkNode
;
47 using bookmarks::BookmarkPermanentNode
;
48 using bookmarks::BookmarkType
;
49 using content::BrowserThread
;
53 class BookmarkNodeCreationTimeCompareFunctor
{
55 bool operator()(const BookmarkNode
* lhs
, const BookmarkNode
* rhs
) {
56 return lhs
->date_added().ToJavaTime() > rhs
->date_added().ToJavaTime();
60 class BookmarkTitleComparer
{
62 explicit BookmarkTitleComparer(BookmarksBridge
* bookmarks_bridge
,
63 const icu::Collator
* collator
)
64 : bookmarks_bridge_(bookmarks_bridge
),
65 collator_(collator
) {}
67 bool operator()(const BookmarkNode
* lhs
, const BookmarkNode
* rhs
) {
69 return base::i18n::CompareString16WithCollator(
70 *collator_
, bookmarks_bridge_
->GetTitle(lhs
),
71 bookmarks_bridge_
->GetTitle(rhs
)) == UCOL_LESS
;
73 return lhs
->GetTitle() < rhs
->GetTitle();
78 BookmarksBridge
* bookmarks_bridge_
; // weak
79 const icu::Collator
* collator_
;
82 scoped_ptr
<icu::Collator
> GetICUCollator() {
83 UErrorCode error
= U_ZERO_ERROR
;
84 scoped_ptr
<icu::Collator
> collator_
;
85 collator_
.reset(icu::Collator::createInstance(error
));
87 collator_
.reset(NULL
);
89 return collator_
.Pass();
94 BookmarksBridge::BookmarksBridge(JNIEnv
* env
, jobject obj
, jobject j_profile
)
95 : weak_java_ref_(env
, obj
),
96 bookmark_model_(NULL
),
97 managed_bookmark_service_(NULL
),
98 partner_bookmarks_shim_(NULL
) {
99 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
100 profile_
= ProfileAndroid::FromProfileAndroid(j_profile
);
101 bookmark_model_
= BookmarkModelFactory::GetForProfile(profile_
);
102 managed_bookmark_service_
=
103 ManagedBookmarkServiceFactory::GetForProfile(profile_
);
105 // Registers the notifications we are interested.
106 bookmark_model_
->AddObserver(this);
108 // Create the partner Bookmarks shim as early as possible (but don't attach).
109 partner_bookmarks_shim_
= PartnerBookmarksShim::BuildForBrowserContext(
110 chrome::GetBrowserContextRedirectedInIncognito(profile_
));
111 partner_bookmarks_shim_
->AddObserver(this);
113 NotifyIfDoneLoading();
115 // Since a sync or import could have started before this class is
116 // initialized, we need to make sure that our initial state is
118 if (bookmark_model_
->IsDoingExtensiveChanges())
119 ExtensiveBookmarkChangesBeginning(bookmark_model_
);
122 BookmarksBridge::~BookmarksBridge() {
123 bookmark_model_
->RemoveObserver(this);
124 if (partner_bookmarks_shim_
)
125 partner_bookmarks_shim_
->RemoveObserver(this);
128 void BookmarksBridge::Destroy(JNIEnv
*, jobject
) {
133 bool BookmarksBridge::RegisterBookmarksBridge(JNIEnv
* env
) {
134 return RegisterNativesImpl(env
);
137 static jlong
Init(JNIEnv
* env
, jobject obj
, jobject j_profile
) {
138 BookmarksBridge
* delegate
= new BookmarksBridge(env
, obj
, j_profile
);
139 return reinterpret_cast<intptr_t>(delegate
);
142 static jboolean
IsEnhancedBookmarksFeatureEnabled(JNIEnv
* env
,
145 return IsEnhancedBookmarksEnabled();
148 jboolean
BookmarksBridge::IsEditBookmarksEnabled(JNIEnv
* env
, jobject obj
) {
149 return IsEditBookmarksEnabled();
152 void BookmarksBridge::LoadEmptyPartnerBookmarkShimForTesting(JNIEnv
* env
,
154 if (partner_bookmarks_shim_
->IsLoaded())
156 partner_bookmarks_shim_
->SetPartnerBookmarksRoot(
157 new BookmarkPermanentNode(0));
158 DCHECK(partner_bookmarks_shim_
->IsLoaded());
161 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetBookmarkByID(JNIEnv
* env
,
166 const BookmarkNode
* node
= GetNodeByID(id
, type
);
167 return node
? CreateJavaBookmark(node
) : ScopedJavaLocalRef
<jobject
>();
170 bool BookmarksBridge::IsDoingExtensiveChanges(JNIEnv
* env
, jobject obj
) {
171 return bookmark_model_
->IsDoingExtensiveChanges();
174 void BookmarksBridge::GetPermanentNodeIDs(JNIEnv
* env
,
176 jobject j_result_obj
) {
177 // TODO(kkimlabs): Remove this function.
180 base::StackVector
<const BookmarkNode
*, 8> permanent_nodes
;
182 // Save all the permanent nodes.
183 const BookmarkNode
* root_node
= bookmark_model_
->root_node();
184 permanent_nodes
->push_back(root_node
);
185 for (int i
= 0; i
< root_node
->child_count(); ++i
) {
186 permanent_nodes
->push_back(root_node
->GetChild(i
));
188 permanent_nodes
->push_back(
189 partner_bookmarks_shim_
->GetPartnerBookmarksRoot());
191 // Write the permanent nodes to |j_result_obj|.
192 for (base::StackVector
<const BookmarkNode
*, 8>::ContainerType::const_iterator
193 it
= permanent_nodes
->begin();
194 it
!= permanent_nodes
->end();
197 Java_BookmarksBridge_addToBookmarkIdList(
198 env
, j_result_obj
, (*it
)->id(), GetBookmarkType(*it
));
203 void BookmarksBridge::GetTopLevelFolderParentIDs(JNIEnv
* env
,
205 jobject j_result_obj
) {
206 Java_BookmarksBridge_addToBookmarkIdList(
207 env
, j_result_obj
, bookmark_model_
->root_node()->id(),
208 GetBookmarkType(bookmark_model_
->root_node()));
211 void BookmarksBridge::GetTopLevelFolderIDs(JNIEnv
* env
,
213 jboolean get_special
,
215 jobject j_result_obj
) {
217 std::vector
<const BookmarkNode
*> top_level_folders
;
220 if (managed_bookmark_service_
->managed_node() &&
221 managed_bookmark_service_
->managed_node()->child_count() > 0) {
222 top_level_folders
.push_back(managed_bookmark_service_
->managed_node());
224 if (managed_bookmark_service_
->supervised_node() &&
225 managed_bookmark_service_
->supervised_node()->child_count() > 0) {
226 top_level_folders
.push_back(managed_bookmark_service_
->supervised_node());
228 if (partner_bookmarks_shim_
->HasPartnerBookmarks()
229 && IsReachable(partner_bookmarks_shim_
->GetPartnerBookmarksRoot())) {
230 top_level_folders
.push_back(
231 partner_bookmarks_shim_
->GetPartnerBookmarksRoot());
234 std::size_t special_count
= top_level_folders
.size();
237 DCHECK_EQ(bookmark_model_
->root_node()->child_count(), 5);
239 const BookmarkNode
* mobile_node
= bookmark_model_
->mobile_node();
240 for (int i
= 0; i
< mobile_node
->child_count(); ++i
) {
241 const BookmarkNode
* node
= mobile_node
->GetChild(i
);
242 if (node
->is_folder()) {
243 top_level_folders
.push_back(node
);
247 const BookmarkNode
* bookmark_bar_node
=
248 bookmark_model_
->bookmark_bar_node();
249 for (int i
= 0; i
< bookmark_bar_node
->child_count(); ++i
) {
250 const BookmarkNode
* node
= bookmark_bar_node
->GetChild(i
);
251 if (node
->is_folder()) {
252 top_level_folders
.push_back(node
);
256 const BookmarkNode
* other_node
= bookmark_model_
->other_node();
257 for (int i
= 0; i
< other_node
->child_count(); ++i
) {
258 const BookmarkNode
* node
= other_node
->GetChild(i
);
259 if (node
->is_folder()) {
260 top_level_folders
.push_back(node
);
264 scoped_ptr
<icu::Collator
> collator
= GetICUCollator();
265 std::stable_sort(top_level_folders
.begin() + special_count
,
266 top_level_folders
.end(),
267 BookmarkTitleComparer(this, collator
.get()));
270 for (std::vector
<const BookmarkNode
*>::const_iterator it
=
271 top_level_folders
.begin(); it
!= top_level_folders
.end(); ++it
) {
272 Java_BookmarksBridge_addToBookmarkIdList(env
,
275 GetBookmarkType(*it
));
279 void BookmarksBridge::GetAllFoldersWithDepths(JNIEnv
* env
,
281 jobject j_folders_obj
,
282 jobject j_depths_obj
) {
285 scoped_ptr
<icu::Collator
> collator
= GetICUCollator();
287 // Vector to temporarily contain all child bookmarks at same level for sorting
288 std::vector
<const BookmarkNode
*> bookmarkList
;
290 // Stack for Depth-First Search of bookmark model. It stores nodes and their
292 std::stack
<std::pair
<const BookmarkNode
*, int> > stk
;
294 bookmarkList
.push_back(bookmark_model_
->mobile_node());
295 bookmarkList
.push_back(bookmark_model_
->bookmark_bar_node());
296 bookmarkList
.push_back(bookmark_model_
->other_node());
298 // Push all sorted top folders in stack and give them depth of 0.
299 // Note the order to push folders to stack should be opposite to the order in
301 for (std::vector
<const BookmarkNode
*>::reverse_iterator it
=
302 bookmarkList
.rbegin();
303 it
!= bookmarkList
.rend();
305 stk
.push(std::make_pair(*it
, 0));
308 while (!stk
.empty()) {
309 const BookmarkNode
* node
= stk
.top().first
;
310 int depth
= stk
.top().second
;
312 Java_BookmarksBridge_addToBookmarkIdListWithDepth(env
,
315 GetBookmarkType(node
),
318 bookmarkList
.clear();
319 for (int i
= 0; i
< node
->child_count(); ++i
) {
320 const BookmarkNode
* child
= node
->GetChild(i
);
321 if (child
->is_folder() &&
322 managed_bookmark_service_
->CanBeEditedByUser(child
)) {
323 bookmarkList
.push_back(node
->GetChild(i
));
326 std::stable_sort(bookmarkList
.begin(),
328 BookmarkTitleComparer(this, collator
.get()));
329 for (std::vector
<const BookmarkNode
*>::reverse_iterator it
=
330 bookmarkList
.rbegin();
331 it
!= bookmarkList
.rend();
333 stk
.push(std::make_pair(*it
, depth
+ 1));
338 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetRootFolderId(JNIEnv
* env
,
340 const BookmarkNode
* root_node
= bookmark_model_
->root_node();
341 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
342 JavaBookmarkIdCreateBookmarkId(
343 env
, root_node
->id(), GetBookmarkType(root_node
));
344 return folder_id_obj
;
347 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetMobileFolderId(JNIEnv
* env
,
349 const BookmarkNode
* mobile_node
= bookmark_model_
->mobile_node();
350 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
351 JavaBookmarkIdCreateBookmarkId(
352 env
, mobile_node
->id(), GetBookmarkType(mobile_node
));
353 return folder_id_obj
;
356 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetOtherFolderId(JNIEnv
* env
,
358 const BookmarkNode
* other_node
= bookmark_model_
->other_node();
359 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
360 JavaBookmarkIdCreateBookmarkId(
361 env
, other_node
->id(), GetBookmarkType(other_node
));
362 return folder_id_obj
;
365 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetDesktopFolderId(JNIEnv
* env
,
367 const BookmarkNode
* desktop_node
= bookmark_model_
->bookmark_bar_node();
368 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
369 JavaBookmarkIdCreateBookmarkId(
370 env
, desktop_node
->id(), GetBookmarkType(desktop_node
));
371 return folder_id_obj
;
374 void BookmarksBridge::GetChildIDs(JNIEnv
* env
,
378 jboolean get_folders
,
379 jboolean get_bookmarks
,
380 jobject j_result_obj
) {
383 const BookmarkNode
* parent
= GetNodeByID(id
, type
);
384 if (!parent
->is_folder() || !IsReachable(parent
))
387 // Get the folder contents
388 for (int i
= 0; i
< parent
->child_count(); ++i
) {
389 const BookmarkNode
* child
= parent
->GetChild(i
);
390 if (!IsFolderAvailable(child
) || !IsReachable(child
))
393 if ((child
->is_folder() && get_folders
) ||
394 (!child
->is_folder() && get_bookmarks
)) {
395 Java_BookmarksBridge_addToBookmarkIdList(
396 env
, j_result_obj
, child
->id(), GetBookmarkType(child
));
400 // Partner bookmark root node is under mobile node.
401 if (parent
== bookmark_model_
->mobile_node() && get_folders
&&
402 partner_bookmarks_shim_
->HasPartnerBookmarks() &&
403 IsReachable(partner_bookmarks_shim_
->GetPartnerBookmarksRoot())) {
404 Java_BookmarksBridge_addToBookmarkIdList(
407 partner_bookmarks_shim_
->GetPartnerBookmarksRoot()->id(),
408 BookmarkType::BOOKMARK_TYPE_PARTNER
);
412 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetChildAt(JNIEnv
* env
,
419 const BookmarkNode
* parent
= GetNodeByID(id
, type
);
421 const BookmarkNode
* child
= parent
->GetChild(index
);
422 return JavaBookmarkIdCreateBookmarkId(
423 env
, child
->id(), GetBookmarkType(child
));
426 void BookmarksBridge::GetAllBookmarkIDsOrderedByCreationDate(
429 jobject j_result_obj
) {
431 std::list
<const BookmarkNode
*> folders
;
432 std::vector
<const BookmarkNode
*> result
;
433 folders
.push_back(bookmark_model_
->root_node());
435 for (std::list
<const BookmarkNode
*>::iterator folder_iter
= folders
.begin();
436 folder_iter
!= folders
.end(); ++folder_iter
) {
437 if (*folder_iter
== NULL
)
440 std::list
<const BookmarkNode
*>::iterator insert_iter
= folder_iter
;
443 for (int i
= 0; i
< (*folder_iter
)->child_count(); ++i
) {
444 const BookmarkNode
* child
= (*folder_iter
)->GetChild(i
);
445 if (!IsReachable(child
) ||
446 bookmarks::IsDescendantOf(
447 child
, managed_bookmark_service_
->managed_node()) ||
448 bookmarks::IsDescendantOf(
449 child
, managed_bookmark_service_
->supervised_node())) {
453 if (child
->is_folder()) {
454 insert_iter
= folders
.insert(insert_iter
, child
);
456 result
.push_back(child
);
462 result
.begin(), result
.end(), BookmarkNodeCreationTimeCompareFunctor());
464 for (std::vector
<const BookmarkNode
*>::const_iterator iter
= result
.begin();
465 iter
!= result
.end();
467 const BookmarkNode
* bookmark
= *iter
;
468 Java_BookmarksBridge_addToBookmarkIdList(
469 env
, j_result_obj
, bookmark
->id(), GetBookmarkType(bookmark
));
473 void BookmarksBridge::SetBookmarkTitle(JNIEnv
* env
,
479 const BookmarkNode
* bookmark
= GetNodeByID(id
, type
);
480 const base::string16 title
=
481 base::android::ConvertJavaStringToUTF16(env
, j_title
);
483 if (partner_bookmarks_shim_
->IsPartnerBookmark(bookmark
)) {
484 partner_bookmarks_shim_
->RenameBookmark(bookmark
, title
);
486 bookmark_model_
->SetTitle(bookmark
, title
);
490 void BookmarksBridge::SetBookmarkUrl(JNIEnv
* env
,
496 bookmark_model_
->SetURL(
497 GetNodeByID(id
, type
),
498 GURL(base::android::ConvertJavaStringToUTF16(env
, url
)));
501 bool BookmarksBridge::DoesBookmarkExist(JNIEnv
* env
,
506 return GetNodeByID(id
, type
);
509 void BookmarksBridge::GetBookmarksForFolder(JNIEnv
* env
,
511 jobject j_folder_id_obj
,
512 jobject j_callback_obj
,
513 jobject j_result_obj
) {
515 long folder_id
= JavaBookmarkIdGetId(env
, j_folder_id_obj
);
516 int type
= JavaBookmarkIdGetType(env
, j_folder_id_obj
);
517 const BookmarkNode
* folder
= GetFolderWithFallback(folder_id
, type
);
519 if (!folder
->is_folder() || !IsReachable(folder
))
522 // Recreate the java bookmarkId object due to fallback.
523 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
524 JavaBookmarkIdCreateBookmarkId(
525 env
, folder
->id(), GetBookmarkType(folder
));
526 j_folder_id_obj
= folder_id_obj
.obj();
528 // Get the folder contents.
529 for (int i
= 0; i
< folder
->child_count(); ++i
) {
530 const BookmarkNode
* node
= folder
->GetChild(i
);
531 if (!IsFolderAvailable(node
))
533 ExtractBookmarkNodeInformation(node
, j_result_obj
);
536 if (folder
== bookmark_model_
->mobile_node() &&
537 partner_bookmarks_shim_
->HasPartnerBookmarks()) {
538 ExtractBookmarkNodeInformation(
539 partner_bookmarks_shim_
->GetPartnerBookmarksRoot(),
543 if (j_callback_obj
) {
544 Java_BookmarksCallback_onBookmarksAvailable(
545 env
, j_callback_obj
, j_folder_id_obj
, j_result_obj
);
549 jboolean
BookmarksBridge::IsFolderVisible(JNIEnv
* env
,
553 if (type
== BookmarkType::BOOKMARK_TYPE_NORMAL
) {
554 const BookmarkNode
* node
= bookmarks::GetBookmarkNodeByID(
555 bookmark_model_
, static_cast<int64
>(id
));
556 return node
->IsVisible();
557 } else if (type
== BookmarkType::BOOKMARK_TYPE_PARTNER
) {
558 const BookmarkNode
* node
= partner_bookmarks_shim_
->GetNodeByID(
559 static_cast<long>(id
));
560 return partner_bookmarks_shim_
->IsReachable(node
);
567 void BookmarksBridge::GetCurrentFolderHierarchy(JNIEnv
* env
,
569 jobject j_folder_id_obj
,
570 jobject j_callback_obj
,
571 jobject j_result_obj
) {
573 long folder_id
= JavaBookmarkIdGetId(env
, j_folder_id_obj
);
574 int type
= JavaBookmarkIdGetType(env
, j_folder_id_obj
);
575 const BookmarkNode
* folder
= GetFolderWithFallback(folder_id
, type
);
577 if (!folder
->is_folder() || !IsReachable(folder
))
580 // Recreate the java bookmarkId object due to fallback.
581 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
582 JavaBookmarkIdCreateBookmarkId(
583 env
, folder
->id(), GetBookmarkType(folder
));
584 j_folder_id_obj
= folder_id_obj
.obj();
586 // Get the folder hierarchy.
587 const BookmarkNode
* node
= folder
;
589 ExtractBookmarkNodeInformation(node
, j_result_obj
);
590 node
= GetParentNode(node
);
593 Java_BookmarksCallback_onBookmarksFolderHierarchyAvailable(
594 env
, j_callback_obj
, j_folder_id_obj
, j_result_obj
);
597 ScopedJavaLocalRef
<jobject
> BookmarksBridge::AddFolder(JNIEnv
* env
,
599 jobject j_parent_id_obj
,
603 long bookmark_id
= JavaBookmarkIdGetId(env
, j_parent_id_obj
);
604 int type
= JavaBookmarkIdGetType(env
, j_parent_id_obj
);
605 const BookmarkNode
* parent
= GetNodeByID(bookmark_id
, type
);
607 const BookmarkNode
* new_node
= bookmark_model_
->AddFolder(
608 parent
, index
, base::android::ConvertJavaStringToUTF16(env
, j_title
));
611 return ScopedJavaLocalRef
<jobject
>();
613 ScopedJavaLocalRef
<jobject
> new_java_obj
=
614 JavaBookmarkIdCreateBookmarkId(
615 env
, new_node
->id(), GetBookmarkType(new_node
));
619 void BookmarksBridge::DeleteBookmark(JNIEnv
* env
,
621 jobject j_bookmark_id_obj
) {
622 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
625 long bookmark_id
= JavaBookmarkIdGetId(env
, j_bookmark_id_obj
);
626 int type
= JavaBookmarkIdGetType(env
, j_bookmark_id_obj
);
627 const BookmarkNode
* node
= GetNodeByID(bookmark_id
, type
);
628 if (!IsEditable(node
)) {
633 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
634 partner_bookmarks_shim_
->RemoveBookmark(node
);
636 bookmark_model_
->Remove(node
);
639 void BookmarksBridge::MoveBookmark(JNIEnv
* env
,
641 jobject j_bookmark_id_obj
,
642 jobject j_parent_id_obj
,
644 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
647 long bookmark_id
= JavaBookmarkIdGetId(env
, j_bookmark_id_obj
);
648 int type
= JavaBookmarkIdGetType(env
, j_bookmark_id_obj
);
649 const BookmarkNode
* node
= GetNodeByID(bookmark_id
, type
);
650 if (!IsEditable(node
)) {
654 bookmark_id
= JavaBookmarkIdGetId(env
, j_parent_id_obj
);
655 type
= JavaBookmarkIdGetType(env
, j_parent_id_obj
);
656 const BookmarkNode
* new_parent_node
= GetNodeByID(bookmark_id
, type
);
657 bookmark_model_
->Move(node
, new_parent_node
, index
);
660 ScopedJavaLocalRef
<jobject
> BookmarksBridge::AddBookmark(
663 jobject j_parent_id_obj
,
668 long bookmark_id
= JavaBookmarkIdGetId(env
, j_parent_id_obj
);
669 int type
= JavaBookmarkIdGetType(env
, j_parent_id_obj
);
670 const BookmarkNode
* parent
= GetNodeByID(bookmark_id
, type
);
672 const BookmarkNode
* new_node
= bookmark_model_
->AddURL(
675 base::android::ConvertJavaStringToUTF16(env
, j_title
),
676 GURL(base::android::ConvertJavaStringToUTF16(env
, j_url
)));
679 return ScopedJavaLocalRef
<jobject
>();
681 ScopedJavaLocalRef
<jobject
> new_java_obj
=
682 JavaBookmarkIdCreateBookmarkId(
683 env
, new_node
->id(), GetBookmarkType(new_node
));
687 void BookmarksBridge::Undo(JNIEnv
* env
, jobject obj
) {
688 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
690 BookmarkUndoService
* undo_service
=
691 BookmarkUndoServiceFactory::GetForProfile(profile_
);
692 UndoManager
* undo_manager
= undo_service
->undo_manager();
693 undo_manager
->Undo();
696 void BookmarksBridge::StartGroupingUndos(JNIEnv
* env
, jobject obj
) {
697 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
699 DCHECK(!grouped_bookmark_actions_
.get()); // shouldn't have started already
700 grouped_bookmark_actions_
.reset(
701 new bookmarks::ScopedGroupBookmarkActions(bookmark_model_
));
704 void BookmarksBridge::EndGroupingUndos(JNIEnv
* env
, jobject obj
) {
705 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
707 DCHECK(grouped_bookmark_actions_
.get()); // should only call after start
708 grouped_bookmark_actions_
.reset();
711 base::string16
BookmarksBridge::GetTitle(const BookmarkNode
* node
) const {
712 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
713 return partner_bookmarks_shim_
->GetTitle(node
);
715 if (node
== bookmark_model_
->bookmark_bar_node()
716 && IsEnhancedBookmarksEnabled()) {
717 return l10n_util::GetStringUTF16(IDS_ENHANCED_BOOKMARK_BAR_FOLDER_NAME
);
720 return node
->GetTitle();
723 ScopedJavaLocalRef
<jobject
> BookmarksBridge::CreateJavaBookmark(
724 const BookmarkNode
* node
) {
725 JNIEnv
* env
= AttachCurrentThread();
727 const BookmarkNode
* parent
= GetParentNode(node
);
728 int64 parent_id
= parent
? parent
->id() : -1;
732 url
= node
->url().spec();
734 return Java_BookmarksBridge_createBookmarkItem(
737 GetBookmarkType(node
),
738 ConvertUTF16ToJavaString(env
, GetTitle(node
)).obj(),
739 ConvertUTF8ToJavaString(env
, url
).obj(),
742 GetBookmarkType(parent
),
747 void BookmarksBridge::ExtractBookmarkNodeInformation(const BookmarkNode
* node
,
748 jobject j_result_obj
) {
749 JNIEnv
* env
= AttachCurrentThread();
750 if (!IsReachable(node
))
752 Java_BookmarksBridge_addToList(
753 env
, j_result_obj
, CreateJavaBookmark(node
).obj());
756 const BookmarkNode
* BookmarksBridge::GetNodeByID(long node_id
, int type
) {
757 const BookmarkNode
* node
;
758 if (type
== BookmarkType::BOOKMARK_TYPE_PARTNER
) {
759 node
= partner_bookmarks_shim_
->GetNodeByID(
760 static_cast<int64
>(node_id
));
762 node
= bookmarks::GetBookmarkNodeByID(bookmark_model_
,
763 static_cast<int64
>(node_id
));
768 const BookmarkNode
* BookmarksBridge::GetFolderWithFallback(long folder_id
,
770 const BookmarkNode
* folder
= GetNodeByID(folder_id
, type
);
771 if (!folder
|| folder
->type() == BookmarkNode::URL
||
772 !IsFolderAvailable(folder
)) {
773 if (!managed_bookmark_service_
->managed_node()->empty())
774 folder
= managed_bookmark_service_
->managed_node();
776 folder
= bookmark_model_
->mobile_node();
781 bool BookmarksBridge::IsEditBookmarksEnabled() const {
782 return profile_
->GetPrefs()->GetBoolean(
783 bookmarks::prefs::kEditBookmarksEnabled
);
786 bool BookmarksBridge::IsEditable(const BookmarkNode
* node
) const {
787 if (!node
|| (node
->type() != BookmarkNode::FOLDER
&&
788 node
->type() != BookmarkNode::URL
)) {
791 if (!IsEditBookmarksEnabled())
793 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
794 return partner_bookmarks_shim_
->IsEditable(node
);
795 return managed_bookmark_service_
->CanBeEditedByUser(node
);
798 bool BookmarksBridge::IsManaged(const BookmarkNode
* node
) const {
799 return bookmarks::IsDescendantOf(node
,
800 managed_bookmark_service_
->managed_node());
803 const BookmarkNode
* BookmarksBridge::GetParentNode(const BookmarkNode
* node
) {
805 if (node
== partner_bookmarks_shim_
->GetPartnerBookmarksRoot()) {
806 return bookmark_model_
->mobile_node();
808 return node
->parent();
812 int BookmarksBridge::GetBookmarkType(const BookmarkNode
* node
) {
813 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
814 return BookmarkType::BOOKMARK_TYPE_PARTNER
;
816 return BookmarkType::BOOKMARK_TYPE_NORMAL
;
819 bool BookmarksBridge::IsReachable(const BookmarkNode
* node
) const {
820 if (!partner_bookmarks_shim_
->IsPartnerBookmark(node
))
822 return partner_bookmarks_shim_
->IsReachable(node
);
825 bool BookmarksBridge::IsLoaded() const {
826 return (bookmark_model_
->loaded() && partner_bookmarks_shim_
->IsLoaded());
829 bool BookmarksBridge::IsFolderAvailable(
830 const BookmarkNode
* folder
) const {
831 // The managed bookmarks folder is not shown if there are no bookmarks
832 // configured via policy.
833 if (folder
== managed_bookmark_service_
->managed_node() && folder
->empty())
835 // Similarly, the supervised bookmarks folder is not shown if there are no
836 // bookmarks configured by the custodian.
837 if (folder
== managed_bookmark_service_
->supervised_node() && folder
->empty())
840 SigninManager
* signin
= SigninManagerFactory::GetForProfile(
841 profile_
->GetOriginalProfile());
842 return (folder
->type() != BookmarkNode::BOOKMARK_BAR
&&
843 folder
->type() != BookmarkNode::OTHER_NODE
) ||
844 (signin
&& signin
->IsAuthenticated());
847 void BookmarksBridge::NotifyIfDoneLoading() {
850 JNIEnv
* env
= AttachCurrentThread();
851 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
854 Java_BookmarksBridge_bookmarkModelLoaded(env
, obj
.obj());
857 // ------------- Observer-related methods ------------- //
859 void BookmarksBridge::BookmarkModelChanged() {
863 // Called when there are changes to the bookmark model. It is most
864 // likely changes to the partner bookmarks.
865 JNIEnv
* env
= AttachCurrentThread();
866 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
869 Java_BookmarksBridge_bookmarkModelChanged(env
, obj
.obj());
872 void BookmarksBridge::BookmarkModelLoaded(BookmarkModel
* model
,
873 bool ids_reassigned
) {
874 NotifyIfDoneLoading();
877 void BookmarksBridge::BookmarkModelBeingDeleted(BookmarkModel
* model
) {
881 JNIEnv
* env
= AttachCurrentThread();
882 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
885 Java_BookmarksBridge_bookmarkModelDeleted(env
, obj
.obj());
888 void BookmarksBridge::BookmarkNodeMoved(BookmarkModel
* model
,
889 const BookmarkNode
* old_parent
,
891 const BookmarkNode
* new_parent
,
896 JNIEnv
* env
= AttachCurrentThread();
897 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
900 Java_BookmarksBridge_bookmarkNodeMoved(
903 CreateJavaBookmark(old_parent
).obj(),
905 CreateJavaBookmark(new_parent
).obj(),
909 void BookmarksBridge::BookmarkNodeAdded(BookmarkModel
* model
,
910 const BookmarkNode
* parent
,
915 JNIEnv
* env
= AttachCurrentThread();
916 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
919 Java_BookmarksBridge_bookmarkNodeAdded(
922 CreateJavaBookmark(parent
).obj(),
926 void BookmarksBridge::BookmarkNodeRemoved(BookmarkModel
* model
,
927 const BookmarkNode
* parent
,
929 const BookmarkNode
* node
,
930 const std::set
<GURL
>& removed_urls
) {
934 JNIEnv
* env
= AttachCurrentThread();
935 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
938 Java_BookmarksBridge_bookmarkNodeRemoved(
941 CreateJavaBookmark(parent
).obj(),
943 CreateJavaBookmark(node
).obj());
946 void BookmarksBridge::BookmarkAllUserNodesRemoved(
947 BookmarkModel
* model
,
948 const std::set
<GURL
>& removed_urls
) {
952 JNIEnv
* env
= AttachCurrentThread();
953 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
956 Java_BookmarksBridge_bookmarkAllUserNodesRemoved(env
, obj
.obj());
959 void BookmarksBridge::BookmarkNodeChanged(BookmarkModel
* model
,
960 const BookmarkNode
* node
) {
964 JNIEnv
* env
= AttachCurrentThread();
965 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
968 Java_BookmarksBridge_bookmarkNodeChanged(
971 CreateJavaBookmark(node
).obj());
974 void BookmarksBridge::BookmarkNodeChildrenReordered(BookmarkModel
* model
,
975 const BookmarkNode
* node
) {
979 JNIEnv
* env
= AttachCurrentThread();
980 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
983 Java_BookmarksBridge_bookmarkNodeChildrenReordered(
986 CreateJavaBookmark(node
).obj());
989 void BookmarksBridge::ExtensiveBookmarkChangesBeginning(BookmarkModel
* model
) {
993 JNIEnv
* env
= AttachCurrentThread();
994 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
997 Java_BookmarksBridge_extensiveBookmarkChangesBeginning(env
, obj
.obj());
1000 void BookmarksBridge::ExtensiveBookmarkChangesEnded(BookmarkModel
* model
) {
1004 JNIEnv
* env
= AttachCurrentThread();
1005 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
1008 Java_BookmarksBridge_extensiveBookmarkChangesEnded(env
, obj
.obj());
1011 void BookmarksBridge::PartnerShimChanged(PartnerBookmarksShim
* shim
) {
1015 BookmarkModelChanged();
1018 void BookmarksBridge::PartnerShimLoaded(PartnerBookmarksShim
* shim
) {
1019 NotifyIfDoneLoading();
1022 void BookmarksBridge::ShimBeingDeleted(PartnerBookmarksShim
* shim
) {
1023 partner_bookmarks_shim_
= NULL
;