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/chrome_bookmark_client_factory.h"
14 #include "chrome/browser/bookmarks/enhanced_bookmarks_features.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/query_parser/query_parser.h"
27 #include "components/signin/core/browser/signin_manager.h"
28 #include "components/undo/bookmark_undo_service.h"
29 #include "components/undo/undo_manager.h"
30 #include "content/public/browser/browser_thread.h"
31 #include "grit/components_strings.h"
32 #include "jni/BookmarksBridge_jni.h"
33 #include "ui/base/l10n/l10n_util.h"
35 using base::android::AttachCurrentThread
;
36 using base::android::ConvertUTF8ToJavaString
;
37 using base::android::ConvertUTF16ToJavaString
;
38 using base::android::ScopedJavaLocalRef
;
39 using base::android::ScopedJavaGlobalRef
;
40 using base::android::ToJavaIntArray
;
41 using bookmarks::android::JavaBookmarkIdCreateBookmarkId
;
42 using bookmarks::android::JavaBookmarkIdGetId
;
43 using bookmarks::android::JavaBookmarkIdGetType
;
44 using bookmarks::BookmarkModel
;
45 using bookmarks::BookmarkNode
;
46 using bookmarks::BookmarkPermanentNode
;
47 using bookmarks::BookmarkType
;
48 using content::BrowserThread
;
52 class BookmarkNodeCreationTimeCompareFunctor
{
54 bool operator()(const BookmarkNode
* lhs
, const BookmarkNode
* rhs
) {
55 return lhs
->date_added().ToJavaTime() > rhs
->date_added().ToJavaTime();
59 class BookmarkTitleComparer
{
61 explicit BookmarkTitleComparer(BookmarksBridge
* bookmarks_bridge
,
62 const icu::Collator
* collator
)
63 : bookmarks_bridge_(bookmarks_bridge
),
64 collator_(collator
) {}
66 bool operator()(const BookmarkNode
* lhs
, const BookmarkNode
* rhs
) {
68 return base::i18n::CompareString16WithCollator(
69 *collator_
, bookmarks_bridge_
->GetTitle(lhs
),
70 bookmarks_bridge_
->GetTitle(rhs
)) == UCOL_LESS
;
72 return lhs
->GetTitle() < rhs
->GetTitle();
77 BookmarksBridge
* bookmarks_bridge_
; // weak
78 const icu::Collator
* collator_
;
81 scoped_ptr
<icu::Collator
> GetICUCollator() {
82 UErrorCode error
= U_ZERO_ERROR
;
83 scoped_ptr
<icu::Collator
> collator_
;
84 collator_
.reset(icu::Collator::createInstance(error
));
86 collator_
.reset(NULL
);
88 return collator_
.Pass();
93 BookmarksBridge::BookmarksBridge(JNIEnv
* env
,
96 : weak_java_ref_(env
, obj
),
97 bookmark_model_(NULL
),
99 partner_bookmarks_shim_(NULL
) {
100 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
101 profile_
= ProfileAndroid::FromProfileAndroid(j_profile
);
102 bookmark_model_
= BookmarkModelFactory::GetForProfile(profile_
);
103 client_
= ChromeBookmarkClientFactory::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 static bool IsEditBookmarksEnabled(Profile
* profile
) {
149 return profile
->GetPrefs()->GetBoolean(
150 bookmarks::prefs::kEditBookmarksEnabled
);
153 static jboolean
IsEditBookmarksEnabled(JNIEnv
* env
,
156 return IsEditBookmarksEnabled(ProfileAndroid::FromProfileAndroid(j_profile
));
159 void BookmarksBridge::LoadEmptyPartnerBookmarkShimForTesting(JNIEnv
* env
,
161 if (partner_bookmarks_shim_
->IsLoaded())
163 partner_bookmarks_shim_
->SetPartnerBookmarksRoot(
164 new BookmarkPermanentNode(0));
165 DCHECK(partner_bookmarks_shim_
->IsLoaded());
168 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetBookmarkByID(JNIEnv
* env
,
173 return CreateJavaBookmark(GetNodeByID(id
, type
));
176 bool BookmarksBridge::IsDoingExtensiveChanges(JNIEnv
* env
, jobject obj
) {
177 return bookmark_model_
->IsDoingExtensiveChanges();
180 void BookmarksBridge::GetPermanentNodeIDs(JNIEnv
* env
,
182 jobject j_result_obj
) {
183 // TODO(kkimlabs): Remove this function.
186 base::StackVector
<const BookmarkNode
*, 8> permanent_nodes
;
188 // Save all the permanent nodes.
189 const BookmarkNode
* root_node
= bookmark_model_
->root_node();
190 permanent_nodes
->push_back(root_node
);
191 for (int i
= 0; i
< root_node
->child_count(); ++i
) {
192 permanent_nodes
->push_back(root_node
->GetChild(i
));
194 permanent_nodes
->push_back(
195 partner_bookmarks_shim_
->GetPartnerBookmarksRoot());
197 // Write the permanent nodes to |j_result_obj|.
198 for (base::StackVector
<const BookmarkNode
*, 8>::ContainerType::const_iterator
199 it
= permanent_nodes
->begin();
200 it
!= permanent_nodes
->end();
203 Java_BookmarksBridge_addToBookmarkIdList(
204 env
, j_result_obj
, (*it
)->id(), GetBookmarkType(*it
));
209 void BookmarksBridge::GetTopLevelFolderParentIDs(JNIEnv
* env
,
211 jobject j_result_obj
) {
212 Java_BookmarksBridge_addToBookmarkIdList(
213 env
, j_result_obj
, bookmark_model_
->root_node()->id(),
214 GetBookmarkType(bookmark_model_
->root_node()));
217 void BookmarksBridge::GetTopLevelFolderIDs(JNIEnv
* env
,
219 jboolean get_special
,
221 jobject j_result_obj
) {
223 std::vector
<const BookmarkNode
*> top_level_folders
;
226 if (client_
->managed_node() &&
227 client_
->managed_node()->child_count() > 0) {
228 top_level_folders
.push_back(client_
->managed_node());
230 if (client_
->supervised_node() &&
231 client_
->supervised_node()->child_count() > 0) {
232 top_level_folders
.push_back(client_
->supervised_node());
234 if (partner_bookmarks_shim_
->HasPartnerBookmarks()
235 && IsReachable(partner_bookmarks_shim_
->GetPartnerBookmarksRoot())) {
236 top_level_folders
.push_back(
237 partner_bookmarks_shim_
->GetPartnerBookmarksRoot());
240 std::size_t special_count
= top_level_folders
.size();
243 DCHECK_EQ(bookmark_model_
->root_node()->child_count(), 5);
245 const BookmarkNode
* mobile_node
= bookmark_model_
->mobile_node();
246 for (int i
= 0; i
< mobile_node
->child_count(); ++i
) {
247 const BookmarkNode
* node
= mobile_node
->GetChild(i
);
248 if (node
->is_folder()) {
249 top_level_folders
.push_back(node
);
253 const BookmarkNode
* bookmark_bar_node
=
254 bookmark_model_
->bookmark_bar_node();
255 for (int i
= 0; i
< bookmark_bar_node
->child_count(); ++i
) {
256 const BookmarkNode
* node
= bookmark_bar_node
->GetChild(i
);
257 if (node
->is_folder()) {
258 top_level_folders
.push_back(node
);
262 const BookmarkNode
* other_node
= bookmark_model_
->other_node();
263 for (int i
= 0; i
< other_node
->child_count(); ++i
) {
264 const BookmarkNode
* node
= other_node
->GetChild(i
);
265 if (node
->is_folder()) {
266 top_level_folders
.push_back(node
);
270 scoped_ptr
<icu::Collator
> collator
= GetICUCollator();
271 std::stable_sort(top_level_folders
.begin() + special_count
,
272 top_level_folders
.end(),
273 BookmarkTitleComparer(this, collator
.get()));
276 for (std::vector
<const BookmarkNode
*>::const_iterator it
=
277 top_level_folders
.begin(); it
!= top_level_folders
.end(); ++it
) {
278 Java_BookmarksBridge_addToBookmarkIdList(env
,
281 GetBookmarkType(*it
));
285 void BookmarksBridge::GetAllFoldersWithDepths(JNIEnv
* env
,
287 jobject j_folders_obj
,
288 jobject j_depths_obj
) {
291 scoped_ptr
<icu::Collator
> collator
= GetICUCollator();
293 // Vector to temporarily contain all child bookmarks at same level for sorting
294 std::vector
<const BookmarkNode
*> bookmarkList
;
296 // Stack for Depth-First Search of bookmark model. It stores nodes and their
298 std::stack
<std::pair
<const BookmarkNode
*, int> > stk
;
300 bookmarkList
.push_back(bookmark_model_
->mobile_node());
301 bookmarkList
.push_back(bookmark_model_
->bookmark_bar_node());
302 bookmarkList
.push_back(bookmark_model_
->other_node());
304 // Push all sorted top folders in stack and give them depth of 0.
305 // Note the order to push folders to stack should be opposite to the order in
307 for (std::vector
<const BookmarkNode
*>::reverse_iterator it
=
308 bookmarkList
.rbegin();
309 it
!= bookmarkList
.rend();
311 stk
.push(std::make_pair(*it
, 0));
314 while (!stk
.empty()) {
315 const BookmarkNode
* node
= stk
.top().first
;
316 int depth
= stk
.top().second
;
318 Java_BookmarksBridge_addToBookmarkIdListWithDepth(env
,
321 GetBookmarkType(node
),
324 bookmarkList
.clear();
325 for (int i
= 0; i
< node
->child_count(); ++i
) {
326 const BookmarkNode
* child
= node
->GetChild(i
);
327 if (child
->is_folder() && client_
->CanBeEditedByUser(child
))
328 bookmarkList
.push_back(node
->GetChild(i
));
330 std::stable_sort(bookmarkList
.begin(),
332 BookmarkTitleComparer(this, collator
.get()));
333 for (std::vector
<const BookmarkNode
*>::reverse_iterator it
=
334 bookmarkList
.rbegin();
335 it
!= bookmarkList
.rend();
337 stk
.push(std::make_pair(*it
, depth
+ 1));
342 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetRootFolderId(JNIEnv
* env
,
344 const BookmarkNode
* root_node
= bookmark_model_
->root_node();
345 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
346 JavaBookmarkIdCreateBookmarkId(
347 env
, root_node
->id(), GetBookmarkType(root_node
));
348 return folder_id_obj
;
351 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetMobileFolderId(JNIEnv
* env
,
353 const BookmarkNode
* mobile_node
= bookmark_model_
->mobile_node();
354 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
355 JavaBookmarkIdCreateBookmarkId(
356 env
, mobile_node
->id(), GetBookmarkType(mobile_node
));
357 return folder_id_obj
;
360 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetOtherFolderId(JNIEnv
* env
,
362 const BookmarkNode
* other_node
= bookmark_model_
->other_node();
363 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
364 JavaBookmarkIdCreateBookmarkId(
365 env
, other_node
->id(), GetBookmarkType(other_node
));
366 return folder_id_obj
;
369 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetDesktopFolderId(JNIEnv
* env
,
371 const BookmarkNode
* desktop_node
= bookmark_model_
->bookmark_bar_node();
372 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
373 JavaBookmarkIdCreateBookmarkId(
374 env
, desktop_node
->id(), GetBookmarkType(desktop_node
));
375 return folder_id_obj
;
378 void BookmarksBridge::GetChildIDs(JNIEnv
* env
,
382 jboolean get_folders
,
383 jboolean get_bookmarks
,
384 jobject j_result_obj
) {
387 const BookmarkNode
* parent
= GetNodeByID(id
, type
);
388 if (!parent
->is_folder() || !IsReachable(parent
))
391 // Get the folder contents
392 for (int i
= 0; i
< parent
->child_count(); ++i
) {
393 const BookmarkNode
* child
= parent
->GetChild(i
);
394 if (!IsFolderAvailable(child
) || !IsReachable(child
))
397 if ((child
->is_folder() && get_folders
) ||
398 (!child
->is_folder() && get_bookmarks
)) {
399 Java_BookmarksBridge_addToBookmarkIdList(
400 env
, j_result_obj
, child
->id(), GetBookmarkType(child
));
404 // Partner bookmark root node is under mobile node.
405 if (parent
== bookmark_model_
->mobile_node() && get_folders
&&
406 partner_bookmarks_shim_
->HasPartnerBookmarks() &&
407 IsReachable(partner_bookmarks_shim_
->GetPartnerBookmarksRoot())) {
408 Java_BookmarksBridge_addToBookmarkIdList(
411 partner_bookmarks_shim_
->GetPartnerBookmarksRoot()->id(),
412 BookmarkType::BOOKMARK_TYPE_PARTNER
);
416 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetChildAt(JNIEnv
* env
,
423 const BookmarkNode
* parent
= GetNodeByID(id
, type
);
425 const BookmarkNode
* child
= parent
->GetChild(index
);
426 return JavaBookmarkIdCreateBookmarkId(
427 env
, child
->id(), GetBookmarkType(child
));
430 void BookmarksBridge::GetAllBookmarkIDsOrderedByCreationDate(
433 jobject j_result_obj
) {
435 std::list
<const BookmarkNode
*> folders
;
436 std::vector
<const BookmarkNode
*> result
;
437 folders
.push_back(bookmark_model_
->root_node());
439 for (std::list
<const BookmarkNode
*>::iterator folder_iter
= folders
.begin();
440 folder_iter
!= folders
.end(); ++folder_iter
) {
441 if (*folder_iter
== NULL
)
444 std::list
<const BookmarkNode
*>::iterator insert_iter
= folder_iter
;
447 for (int i
= 0; i
< (*folder_iter
)->child_count(); ++i
) {
448 const BookmarkNode
* child
= (*folder_iter
)->GetChild(i
);
449 if (!IsReachable(child
) ||
450 bookmarks::IsDescendantOf(child
, client_
->managed_node()) ||
451 bookmarks::IsDescendantOf(child
, client_
->supervised_node())) {
455 if (child
->is_folder()) {
456 insert_iter
= folders
.insert(insert_iter
, child
);
458 result
.push_back(child
);
464 result
.begin(), result
.end(), BookmarkNodeCreationTimeCompareFunctor());
466 for (std::vector
<const BookmarkNode
*>::const_iterator iter
= result
.begin();
467 iter
!= result
.end();
469 const BookmarkNode
* bookmark
= *iter
;
470 Java_BookmarksBridge_addToBookmarkIdList(
471 env
, j_result_obj
, bookmark
->id(), GetBookmarkType(bookmark
));
475 void BookmarksBridge::SetBookmarkTitle(JNIEnv
* env
,
481 const BookmarkNode
* bookmark
= GetNodeByID(id
, type
);
482 const base::string16 title
=
483 base::android::ConvertJavaStringToUTF16(env
, j_title
);
485 if (partner_bookmarks_shim_
->IsPartnerBookmark(bookmark
)) {
486 partner_bookmarks_shim_
->RenameBookmark(bookmark
, title
);
488 bookmark_model_
->SetTitle(bookmark
, title
);
492 void BookmarksBridge::SetBookmarkUrl(JNIEnv
* env
,
498 bookmark_model_
->SetURL(
499 GetNodeByID(id
, type
),
500 GURL(base::android::ConvertJavaStringToUTF16(env
, url
)));
503 bool BookmarksBridge::DoesBookmarkExist(JNIEnv
* env
,
508 return GetNodeByID(id
, type
);
511 void BookmarksBridge::GetBookmarksForFolder(JNIEnv
* env
,
513 jobject j_folder_id_obj
,
514 jobject j_callback_obj
,
515 jobject j_result_obj
) {
517 long folder_id
= JavaBookmarkIdGetId(env
, j_folder_id_obj
);
518 int type
= JavaBookmarkIdGetType(env
, j_folder_id_obj
);
519 const BookmarkNode
* folder
= GetFolderWithFallback(folder_id
, type
);
521 if (!folder
->is_folder() || !IsReachable(folder
))
524 // Recreate the java bookmarkId object due to fallback.
525 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
526 JavaBookmarkIdCreateBookmarkId(
527 env
, folder
->id(), GetBookmarkType(folder
));
528 j_folder_id_obj
= folder_id_obj
.obj();
530 // Get the folder contents.
531 for (int i
= 0; i
< folder
->child_count(); ++i
) {
532 const BookmarkNode
* node
= folder
->GetChild(i
);
533 if (!IsFolderAvailable(node
))
535 ExtractBookmarkNodeInformation(node
, j_result_obj
);
538 if (folder
== bookmark_model_
->mobile_node() &&
539 partner_bookmarks_shim_
->HasPartnerBookmarks()) {
540 ExtractBookmarkNodeInformation(
541 partner_bookmarks_shim_
->GetPartnerBookmarksRoot(),
545 if (j_callback_obj
) {
546 Java_BookmarksCallback_onBookmarksAvailable(
547 env
, j_callback_obj
, j_folder_id_obj
, j_result_obj
);
551 jint
BookmarksBridge::GetBookmarkCountForFolder(JNIEnv
* env
,
553 jobject j_folder_id_obj
) {
555 long folder_id
= JavaBookmarkIdGetId(env
, j_folder_id_obj
);
556 int type
= JavaBookmarkIdGetType(env
, j_folder_id_obj
);
557 const BookmarkNode
* folder
= GetNodeByID(folder_id
, type
);
559 if (!folder
|| !IsFolderAvailable(folder
) || !folder
->is_folder()
560 || !IsReachable(folder
))
563 return folder
->child_count();
566 void BookmarksBridge::GetCurrentFolderHierarchy(JNIEnv
* env
,
568 jobject j_folder_id_obj
,
569 jobject j_callback_obj
,
570 jobject j_result_obj
) {
572 long folder_id
= JavaBookmarkIdGetId(env
, j_folder_id_obj
);
573 int type
= JavaBookmarkIdGetType(env
, j_folder_id_obj
);
574 const BookmarkNode
* folder
= GetFolderWithFallback(folder_id
, type
);
576 if (!folder
->is_folder() || !IsReachable(folder
))
579 // Recreate the java bookmarkId object due to fallback.
580 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
581 JavaBookmarkIdCreateBookmarkId(
582 env
, folder
->id(), GetBookmarkType(folder
));
583 j_folder_id_obj
= folder_id_obj
.obj();
585 // Get the folder hierarchy.
586 const BookmarkNode
* node
= folder
;
588 ExtractBookmarkNodeInformation(node
, j_result_obj
);
589 node
= GetParentNode(node
);
592 Java_BookmarksCallback_onBookmarksFolderHierarchyAvailable(
593 env
, j_callback_obj
, j_folder_id_obj
, j_result_obj
);
596 ScopedJavaLocalRef
<jobject
> BookmarksBridge::AddFolder(JNIEnv
* env
,
598 jobject j_parent_id_obj
,
602 long bookmark_id
= JavaBookmarkIdGetId(env
, j_parent_id_obj
);
603 int type
= JavaBookmarkIdGetType(env
, j_parent_id_obj
);
604 const BookmarkNode
* parent
= GetNodeByID(bookmark_id
, type
);
606 const BookmarkNode
* new_node
= bookmark_model_
->AddFolder(
607 parent
, index
, base::android::ConvertJavaStringToUTF16(env
, j_title
));
610 return ScopedJavaLocalRef
<jobject
>();
612 ScopedJavaLocalRef
<jobject
> new_java_obj
=
613 JavaBookmarkIdCreateBookmarkId(
614 env
, new_node
->id(), GetBookmarkType(new_node
));
618 void BookmarksBridge::DeleteBookmark(JNIEnv
* env
,
620 jobject j_bookmark_id_obj
) {
621 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
624 long bookmark_id
= JavaBookmarkIdGetId(env
, j_bookmark_id_obj
);
625 int type
= JavaBookmarkIdGetType(env
, j_bookmark_id_obj
);
626 const BookmarkNode
* node
= GetNodeByID(bookmark_id
, type
);
627 if (!IsEditable(node
)) {
632 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
633 partner_bookmarks_shim_
->RemoveBookmark(node
);
635 bookmark_model_
->Remove(node
);
638 void BookmarksBridge::MoveBookmark(JNIEnv
* env
,
640 jobject j_bookmark_id_obj
,
641 jobject j_parent_id_obj
,
643 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
646 long bookmark_id
= JavaBookmarkIdGetId(env
, j_bookmark_id_obj
);
647 int type
= JavaBookmarkIdGetType(env
, j_bookmark_id_obj
);
648 const BookmarkNode
* node
= GetNodeByID(bookmark_id
, type
);
649 if (!IsEditable(node
)) {
653 bookmark_id
= JavaBookmarkIdGetId(env
, j_parent_id_obj
);
654 type
= JavaBookmarkIdGetType(env
, j_parent_id_obj
);
655 const BookmarkNode
* new_parent_node
= GetNodeByID(bookmark_id
, type
);
656 bookmark_model_
->Move(node
, new_parent_node
, index
);
659 void BookmarksBridge::SearchBookmarks(JNIEnv
* env
,
664 DCHECK(bookmark_model_
->loaded());
666 std::vector
<bookmarks::BookmarkMatch
> results
;
667 bookmark_model_
->GetBookmarksMatching(
668 base::android::ConvertJavaStringToUTF16(env
, j_query
),
670 query_parser::MatchingAlgorithm::ALWAYS_PREFIX_SEARCH
,
672 for (const bookmarks::BookmarkMatch
& match
: results
) {
673 const BookmarkNode
* node
= match
.node
;
675 std::vector
<int> title_match_start_positions
;
676 std::vector
<int> title_match_end_positions
;
677 for (auto position
: match
.title_match_positions
) {
678 title_match_start_positions
.push_back(position
.first
);
679 title_match_end_positions
.push_back(position
.second
);
682 std::vector
<int> url_match_start_positions
;
683 std::vector
<int> url_match_end_positions
;
684 for (auto position
: match
.url_match_positions
) {
685 url_match_start_positions
.push_back(position
.first
);
686 url_match_end_positions
.push_back(position
.second
);
689 Java_BookmarksBridge_addToBookmarkMatchList(
690 env
, j_list
, node
->id(), node
->type(),
691 ToJavaIntArray(env
, title_match_start_positions
).obj(),
692 ToJavaIntArray(env
, title_match_end_positions
).obj(),
693 ToJavaIntArray(env
, url_match_start_positions
).obj(),
694 ToJavaIntArray(env
, url_match_end_positions
).obj());
698 ScopedJavaLocalRef
<jobject
> BookmarksBridge::AddBookmark(
701 jobject j_parent_id_obj
,
706 long bookmark_id
= JavaBookmarkIdGetId(env
, j_parent_id_obj
);
707 int type
= JavaBookmarkIdGetType(env
, j_parent_id_obj
);
708 const BookmarkNode
* parent
= GetNodeByID(bookmark_id
, type
);
710 const BookmarkNode
* new_node
= bookmark_model_
->AddURL(
713 base::android::ConvertJavaStringToUTF16(env
, j_title
),
714 GURL(base::android::ConvertJavaStringToUTF16(env
, j_url
)));
717 return ScopedJavaLocalRef
<jobject
>();
719 ScopedJavaLocalRef
<jobject
> new_java_obj
=
720 JavaBookmarkIdCreateBookmarkId(
721 env
, new_node
->id(), GetBookmarkType(new_node
));
725 void BookmarksBridge::Undo(JNIEnv
* env
, jobject obj
) {
726 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
728 BookmarkUndoService
* undo_service
=
729 BookmarkUndoServiceFactory::GetForProfile(profile_
);
730 UndoManager
* undo_manager
= undo_service
->undo_manager();
731 undo_manager
->Undo();
734 void BookmarksBridge::StartGroupingUndos(JNIEnv
* env
, jobject obj
) {
735 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
737 DCHECK(!grouped_bookmark_actions_
.get()); // shouldn't have started already
738 grouped_bookmark_actions_
.reset(
739 new bookmarks::ScopedGroupBookmarkActions(bookmark_model_
));
742 void BookmarksBridge::EndGroupingUndos(JNIEnv
* env
, jobject obj
) {
743 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
745 DCHECK(grouped_bookmark_actions_
.get()); // should only call after start
746 grouped_bookmark_actions_
.reset();
749 base::string16
BookmarksBridge::GetTitle(const BookmarkNode
* node
) const {
750 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
751 return partner_bookmarks_shim_
->GetTitle(node
);
753 if (node
== bookmark_model_
->bookmark_bar_node()
754 && IsEnhancedBookmarksEnabled()) {
755 return l10n_util::GetStringUTF16(IDS_ENHANCED_BOOKMARK_BAR_FOLDER_NAME
);
758 return node
->GetTitle();
761 ScopedJavaLocalRef
<jobject
> BookmarksBridge::CreateJavaBookmark(
762 const BookmarkNode
* node
) {
763 JNIEnv
* env
= AttachCurrentThread();
765 const BookmarkNode
* parent
= GetParentNode(node
);
766 int64 parent_id
= parent
? parent
->id() : -1;
770 url
= node
->url().spec();
772 return Java_BookmarksBridge_createBookmarkItem(
775 GetBookmarkType(node
),
776 ConvertUTF16ToJavaString(env
, GetTitle(node
)).obj(),
777 ConvertUTF8ToJavaString(env
, url
).obj(),
780 GetBookmarkType(parent
),
785 void BookmarksBridge::ExtractBookmarkNodeInformation(const BookmarkNode
* node
,
786 jobject j_result_obj
) {
787 JNIEnv
* env
= AttachCurrentThread();
788 if (!IsReachable(node
))
790 Java_BookmarksBridge_addToList(
791 env
, j_result_obj
, CreateJavaBookmark(node
).obj());
794 const BookmarkNode
* BookmarksBridge::GetNodeByID(long node_id
, int type
) {
795 const BookmarkNode
* node
;
796 if (type
== BookmarkType::BOOKMARK_TYPE_PARTNER
) {
797 node
= partner_bookmarks_shim_
->GetNodeByID(
798 static_cast<int64
>(node_id
));
800 node
= bookmarks::GetBookmarkNodeByID(bookmark_model_
,
801 static_cast<int64
>(node_id
));
806 const BookmarkNode
* BookmarksBridge::GetFolderWithFallback(long folder_id
,
808 const BookmarkNode
* folder
= GetNodeByID(folder_id
, type
);
809 if (!folder
|| folder
->type() == BookmarkNode::URL
||
810 !IsFolderAvailable(folder
)) {
811 if (!client_
->managed_node()->empty())
812 folder
= client_
->managed_node();
814 folder
= bookmark_model_
->mobile_node();
819 bool BookmarksBridge::IsEditable(const BookmarkNode
* node
) const {
820 if (!node
|| (node
->type() != BookmarkNode::FOLDER
&&
821 node
->type() != BookmarkNode::URL
)) {
824 if (!IsEditBookmarksEnabled(profile_
))
826 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
827 return partner_bookmarks_shim_
->IsEditable(node
);
828 return client_
->CanBeEditedByUser(node
);
831 bool BookmarksBridge::IsManaged(const BookmarkNode
* node
) const {
832 return bookmarks::IsDescendantOf(node
, client_
->managed_node());
835 const BookmarkNode
* BookmarksBridge::GetParentNode(const BookmarkNode
* node
) {
837 if (node
== partner_bookmarks_shim_
->GetPartnerBookmarksRoot()) {
838 return bookmark_model_
->mobile_node();
840 return node
->parent();
844 int BookmarksBridge::GetBookmarkType(const BookmarkNode
* node
) {
845 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
846 return BookmarkType::BOOKMARK_TYPE_PARTNER
;
848 return BookmarkType::BOOKMARK_TYPE_NORMAL
;
851 bool BookmarksBridge::IsReachable(const BookmarkNode
* node
) const {
852 if (!partner_bookmarks_shim_
->IsPartnerBookmark(node
))
854 return partner_bookmarks_shim_
->IsReachable(node
);
857 bool BookmarksBridge::IsLoaded() const {
858 return (bookmark_model_
->loaded() && partner_bookmarks_shim_
->IsLoaded());
861 bool BookmarksBridge::IsFolderAvailable(
862 const BookmarkNode
* folder
) const {
863 // The managed bookmarks folder is not shown if there are no bookmarks
864 // configured via policy.
865 if (folder
== client_
->managed_node() && folder
->empty())
867 // Similarly, the supervised bookmarks folder is not shown if there are no
868 // bookmarks configured by the custodian.
869 if (folder
== client_
->supervised_node() && folder
->empty())
872 SigninManager
* signin
= SigninManagerFactory::GetForProfile(
873 profile_
->GetOriginalProfile());
874 return (folder
->type() != BookmarkNode::BOOKMARK_BAR
&&
875 folder
->type() != BookmarkNode::OTHER_NODE
) ||
876 (signin
&& signin
->IsAuthenticated());
879 void BookmarksBridge::NotifyIfDoneLoading() {
882 JNIEnv
* env
= AttachCurrentThread();
883 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
886 Java_BookmarksBridge_bookmarkModelLoaded(env
, obj
.obj());
889 // ------------- Observer-related methods ------------- //
891 void BookmarksBridge::BookmarkModelChanged() {
895 // Called when there are changes to the bookmark model. It is most
896 // likely changes to the partner bookmarks.
897 JNIEnv
* env
= AttachCurrentThread();
898 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
901 Java_BookmarksBridge_bookmarkModelChanged(env
, obj
.obj());
904 void BookmarksBridge::BookmarkModelLoaded(BookmarkModel
* model
,
905 bool ids_reassigned
) {
906 NotifyIfDoneLoading();
909 void BookmarksBridge::BookmarkModelBeingDeleted(BookmarkModel
* model
) {
913 JNIEnv
* env
= AttachCurrentThread();
914 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
917 Java_BookmarksBridge_bookmarkModelDeleted(env
, obj
.obj());
920 void BookmarksBridge::BookmarkNodeMoved(BookmarkModel
* model
,
921 const BookmarkNode
* old_parent
,
923 const BookmarkNode
* new_parent
,
928 JNIEnv
* env
= AttachCurrentThread();
929 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
932 Java_BookmarksBridge_bookmarkNodeMoved(
935 CreateJavaBookmark(old_parent
).obj(),
937 CreateJavaBookmark(new_parent
).obj(),
941 void BookmarksBridge::BookmarkNodeAdded(BookmarkModel
* model
,
942 const BookmarkNode
* parent
,
947 JNIEnv
* env
= AttachCurrentThread();
948 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
951 Java_BookmarksBridge_bookmarkNodeAdded(
954 CreateJavaBookmark(parent
).obj(),
958 void BookmarksBridge::BookmarkNodeRemoved(BookmarkModel
* model
,
959 const BookmarkNode
* parent
,
961 const BookmarkNode
* node
,
962 const std::set
<GURL
>& removed_urls
) {
966 JNIEnv
* env
= AttachCurrentThread();
967 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
970 Java_BookmarksBridge_bookmarkNodeRemoved(
973 CreateJavaBookmark(parent
).obj(),
975 CreateJavaBookmark(node
).obj());
978 void BookmarksBridge::BookmarkAllUserNodesRemoved(
979 BookmarkModel
* model
,
980 const std::set
<GURL
>& removed_urls
) {
984 JNIEnv
* env
= AttachCurrentThread();
985 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
988 Java_BookmarksBridge_bookmarkAllUserNodesRemoved(env
, obj
.obj());
991 void BookmarksBridge::BookmarkNodeChanged(BookmarkModel
* model
,
992 const BookmarkNode
* node
) {
996 JNIEnv
* env
= AttachCurrentThread();
997 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
1000 Java_BookmarksBridge_bookmarkNodeChanged(
1003 CreateJavaBookmark(node
).obj());
1006 void BookmarksBridge::BookmarkNodeChildrenReordered(BookmarkModel
* model
,
1007 const BookmarkNode
* node
) {
1011 JNIEnv
* env
= AttachCurrentThread();
1012 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
1015 Java_BookmarksBridge_bookmarkNodeChildrenReordered(
1018 CreateJavaBookmark(node
).obj());
1021 void BookmarksBridge::ExtensiveBookmarkChangesBeginning(BookmarkModel
* model
) {
1025 JNIEnv
* env
= AttachCurrentThread();
1026 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
1029 Java_BookmarksBridge_extensiveBookmarkChangesBeginning(env
, obj
.obj());
1032 void BookmarksBridge::ExtensiveBookmarkChangesEnded(BookmarkModel
* model
) {
1036 JNIEnv
* env
= AttachCurrentThread();
1037 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
1040 Java_BookmarksBridge_extensiveBookmarkChangesEnded(env
, obj
.obj());
1043 void BookmarksBridge::PartnerShimChanged(PartnerBookmarksShim
* shim
) {
1047 BookmarkModelChanged();
1050 void BookmarksBridge::PartnerShimLoaded(PartnerBookmarksShim
* shim
) {
1051 NotifyIfDoneLoading();
1054 void BookmarksBridge::ShimBeingDeleted(PartnerBookmarksShim
* shim
) {
1055 partner_bookmarks_shim_
= NULL
;