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.h"
20 #include "chrome/browser/undo/bookmark_undo_service_factory.h"
21 #include "chrome/browser/undo/undo_manager.h"
22 #include "chrome/common/pref_names.h"
23 #include "components/bookmarks/browser/bookmark_match.h"
24 #include "components/bookmarks/browser/bookmark_model.h"
25 #include "components/bookmarks/browser/bookmark_utils.h"
26 #include "components/bookmarks/browser/scoped_group_bookmark_actions.h"
27 #include "components/bookmarks/common/android/bookmark_type.h"
28 #include "components/query_parser/query_parser.h"
29 #include "components/signin/core/browser/signin_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 void BookmarksBridge::GetCurrentFolderHierarchy(JNIEnv
* env
,
553 jobject j_folder_id_obj
,
554 jobject j_callback_obj
,
555 jobject j_result_obj
) {
557 long folder_id
= JavaBookmarkIdGetId(env
, j_folder_id_obj
);
558 int type
= JavaBookmarkIdGetType(env
, j_folder_id_obj
);
559 const BookmarkNode
* folder
= GetFolderWithFallback(folder_id
, type
);
561 if (!folder
->is_folder() || !IsReachable(folder
))
564 // Recreate the java bookmarkId object due to fallback.
565 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
566 JavaBookmarkIdCreateBookmarkId(
567 env
, folder
->id(), GetBookmarkType(folder
));
568 j_folder_id_obj
= folder_id_obj
.obj();
570 // Get the folder hierarchy.
571 const BookmarkNode
* node
= folder
;
573 ExtractBookmarkNodeInformation(node
, j_result_obj
);
574 node
= GetParentNode(node
);
577 Java_BookmarksCallback_onBookmarksFolderHierarchyAvailable(
578 env
, j_callback_obj
, j_folder_id_obj
, j_result_obj
);
581 ScopedJavaLocalRef
<jobject
> BookmarksBridge::AddFolder(JNIEnv
* env
,
583 jobject j_parent_id_obj
,
587 long bookmark_id
= JavaBookmarkIdGetId(env
, j_parent_id_obj
);
588 int type
= JavaBookmarkIdGetType(env
, j_parent_id_obj
);
589 const BookmarkNode
* parent
= GetNodeByID(bookmark_id
, type
);
591 const BookmarkNode
* new_node
= bookmark_model_
->AddFolder(
592 parent
, index
, base::android::ConvertJavaStringToUTF16(env
, j_title
));
595 return ScopedJavaLocalRef
<jobject
>();
597 ScopedJavaLocalRef
<jobject
> new_java_obj
=
598 JavaBookmarkIdCreateBookmarkId(
599 env
, new_node
->id(), GetBookmarkType(new_node
));
603 void BookmarksBridge::DeleteBookmark(JNIEnv
* env
,
605 jobject j_bookmark_id_obj
) {
606 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
609 long bookmark_id
= JavaBookmarkIdGetId(env
, j_bookmark_id_obj
);
610 int type
= JavaBookmarkIdGetType(env
, j_bookmark_id_obj
);
611 const BookmarkNode
* node
= GetNodeByID(bookmark_id
, type
);
612 if (!IsEditable(node
)) {
617 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
)) {
618 partner_bookmarks_shim_
->RemoveBookmark(node
);
620 const BookmarkNode
* parent_node
= GetParentNode(node
);
621 bookmark_model_
->Remove(parent_node
, parent_node
->GetIndexOf(node
));
625 void BookmarksBridge::MoveBookmark(JNIEnv
* env
,
627 jobject j_bookmark_id_obj
,
628 jobject j_parent_id_obj
,
630 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
633 long bookmark_id
= JavaBookmarkIdGetId(env
, j_bookmark_id_obj
);
634 int type
= JavaBookmarkIdGetType(env
, j_bookmark_id_obj
);
635 const BookmarkNode
* node
= GetNodeByID(bookmark_id
, type
);
636 if (!IsEditable(node
)) {
640 bookmark_id
= JavaBookmarkIdGetId(env
, j_parent_id_obj
);
641 type
= JavaBookmarkIdGetType(env
, j_parent_id_obj
);
642 const BookmarkNode
* new_parent_node
= GetNodeByID(bookmark_id
, type
);
643 bookmark_model_
->Move(node
, new_parent_node
, index
);
646 void BookmarksBridge::SearchBookmarks(JNIEnv
* env
,
651 DCHECK(bookmark_model_
->loaded());
653 std::vector
<bookmarks::BookmarkMatch
> results
;
654 bookmark_model_
->GetBookmarksMatching(
655 base::android::ConvertJavaStringToUTF16(env
, j_query
),
657 query_parser::MatchingAlgorithm::ALWAYS_PREFIX_SEARCH
,
659 for (const bookmarks::BookmarkMatch
& match
: results
) {
660 const BookmarkNode
* node
= match
.node
;
662 std::vector
<int> title_match_start_positions
;
663 std::vector
<int> title_match_end_positions
;
664 for (auto position
: match
.title_match_positions
) {
665 title_match_start_positions
.push_back(position
.first
);
666 title_match_end_positions
.push_back(position
.second
);
669 std::vector
<int> url_match_start_positions
;
670 std::vector
<int> url_match_end_positions
;
671 for (auto position
: match
.url_match_positions
) {
672 url_match_start_positions
.push_back(position
.first
);
673 url_match_end_positions
.push_back(position
.second
);
676 Java_BookmarksBridge_addToBookmarkMatchList(
677 env
, j_list
, node
->id(), node
->type(),
678 ToJavaIntArray(env
, title_match_start_positions
).obj(),
679 ToJavaIntArray(env
, title_match_end_positions
).obj(),
680 ToJavaIntArray(env
, url_match_start_positions
).obj(),
681 ToJavaIntArray(env
, url_match_end_positions
).obj());
685 ScopedJavaLocalRef
<jobject
> BookmarksBridge::AddBookmark(
688 jobject j_parent_id_obj
,
693 long bookmark_id
= JavaBookmarkIdGetId(env
, j_parent_id_obj
);
694 int type
= JavaBookmarkIdGetType(env
, j_parent_id_obj
);
695 const BookmarkNode
* parent
= GetNodeByID(bookmark_id
, type
);
697 const BookmarkNode
* new_node
= bookmark_model_
->AddURL(
700 base::android::ConvertJavaStringToUTF16(env
, j_title
),
701 GURL(base::android::ConvertJavaStringToUTF16(env
, j_url
)));
704 return ScopedJavaLocalRef
<jobject
>();
706 ScopedJavaLocalRef
<jobject
> new_java_obj
=
707 JavaBookmarkIdCreateBookmarkId(
708 env
, new_node
->id(), GetBookmarkType(new_node
));
712 void BookmarksBridge::Undo(JNIEnv
* env
, jobject obj
) {
713 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
715 BookmarkUndoService
* undo_service
=
716 BookmarkUndoServiceFactory::GetForProfile(profile_
);
717 UndoManager
* undo_manager
= undo_service
->undo_manager();
718 undo_manager
->Undo();
721 void BookmarksBridge::StartGroupingUndos(JNIEnv
* env
, jobject obj
) {
722 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
724 DCHECK(!grouped_bookmark_actions_
.get()); // shouldn't have started already
725 grouped_bookmark_actions_
.reset(
726 new bookmarks::ScopedGroupBookmarkActions(bookmark_model_
));
729 void BookmarksBridge::EndGroupingUndos(JNIEnv
* env
, jobject obj
) {
730 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
732 DCHECK(grouped_bookmark_actions_
.get()); // should only call after start
733 grouped_bookmark_actions_
.reset();
736 base::string16
BookmarksBridge::GetTitle(const BookmarkNode
* node
) const {
737 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
738 return partner_bookmarks_shim_
->GetTitle(node
);
740 if (node
== bookmark_model_
->bookmark_bar_node()
741 && IsEnhancedBookmarksEnabled()) {
742 return l10n_util::GetStringUTF16(IDS_ENHANCED_BOOKMARK_BAR_FOLDER_NAME
);
745 return node
->GetTitle();
748 ScopedJavaLocalRef
<jobject
> BookmarksBridge::CreateJavaBookmark(
749 const BookmarkNode
* node
) {
750 JNIEnv
* env
= AttachCurrentThread();
752 const BookmarkNode
* parent
= GetParentNode(node
);
753 int64 parent_id
= parent
? parent
->id() : -1;
757 url
= node
->url().spec();
759 return Java_BookmarksBridge_createBookmarkItem(
762 GetBookmarkType(node
),
763 ConvertUTF16ToJavaString(env
, GetTitle(node
)).obj(),
764 ConvertUTF8ToJavaString(env
, url
).obj(),
767 GetBookmarkType(parent
),
772 void BookmarksBridge::ExtractBookmarkNodeInformation(const BookmarkNode
* node
,
773 jobject j_result_obj
) {
774 JNIEnv
* env
= AttachCurrentThread();
775 if (!IsReachable(node
))
777 Java_BookmarksBridge_addToList(
778 env
, j_result_obj
, CreateJavaBookmark(node
).obj());
781 const BookmarkNode
* BookmarksBridge::GetNodeByID(long node_id
, int type
) {
782 const BookmarkNode
* node
;
783 if (type
== BookmarkType::BOOKMARK_TYPE_PARTNER
) {
784 node
= partner_bookmarks_shim_
->GetNodeByID(
785 static_cast<int64
>(node_id
));
787 node
= bookmarks::GetBookmarkNodeByID(bookmark_model_
,
788 static_cast<int64
>(node_id
));
793 const BookmarkNode
* BookmarksBridge::GetFolderWithFallback(long folder_id
,
795 const BookmarkNode
* folder
= GetNodeByID(folder_id
, type
);
796 if (!folder
|| folder
->type() == BookmarkNode::URL
||
797 !IsFolderAvailable(folder
)) {
798 if (!client_
->managed_node()->empty())
799 folder
= client_
->managed_node();
801 folder
= bookmark_model_
->mobile_node();
806 bool BookmarksBridge::IsEditable(const BookmarkNode
* node
) const {
807 if (!node
|| (node
->type() != BookmarkNode::FOLDER
&&
808 node
->type() != BookmarkNode::URL
)) {
811 if (!IsEditBookmarksEnabled(profile_
))
813 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
814 return partner_bookmarks_shim_
->IsEditable(node
);
815 return client_
->CanBeEditedByUser(node
);
818 bool BookmarksBridge::IsManaged(const BookmarkNode
* node
) const {
819 return bookmarks::IsDescendantOf(node
, client_
->managed_node());
822 const BookmarkNode
* BookmarksBridge::GetParentNode(const BookmarkNode
* node
) {
824 if (node
== partner_bookmarks_shim_
->GetPartnerBookmarksRoot()) {
825 return bookmark_model_
->mobile_node();
827 return node
->parent();
831 int BookmarksBridge::GetBookmarkType(const BookmarkNode
* node
) {
832 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
833 return BookmarkType::BOOKMARK_TYPE_PARTNER
;
835 return BookmarkType::BOOKMARK_TYPE_NORMAL
;
838 bool BookmarksBridge::IsReachable(const BookmarkNode
* node
) const {
839 if (!partner_bookmarks_shim_
->IsPartnerBookmark(node
))
841 return partner_bookmarks_shim_
->IsReachable(node
);
844 bool BookmarksBridge::IsLoaded() const {
845 return (bookmark_model_
->loaded() && partner_bookmarks_shim_
->IsLoaded());
848 bool BookmarksBridge::IsFolderAvailable(
849 const BookmarkNode
* folder
) const {
850 // The managed bookmarks folder is not shown if there are no bookmarks
851 // configured via policy.
852 if (folder
== client_
->managed_node() && folder
->empty())
854 // Similarly, the supervised bookmarks folder is not shown if there are no
855 // bookmarks configured by the custodian.
856 if (folder
== client_
->supervised_node() && folder
->empty())
859 SigninManager
* signin
= SigninManagerFactory::GetForProfile(
860 profile_
->GetOriginalProfile());
861 return (folder
->type() != BookmarkNode::BOOKMARK_BAR
&&
862 folder
->type() != BookmarkNode::OTHER_NODE
) ||
863 (signin
&& signin
->IsAuthenticated());
866 void BookmarksBridge::NotifyIfDoneLoading() {
869 JNIEnv
* env
= AttachCurrentThread();
870 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
873 Java_BookmarksBridge_bookmarkModelLoaded(env
, obj
.obj());
876 // ------------- Observer-related methods ------------- //
878 void BookmarksBridge::BookmarkModelChanged() {
882 // Called when there are changes to the bookmark model. It is most
883 // likely changes to the partner bookmarks.
884 JNIEnv
* env
= AttachCurrentThread();
885 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
888 Java_BookmarksBridge_bookmarkModelChanged(env
, obj
.obj());
891 void BookmarksBridge::BookmarkModelLoaded(BookmarkModel
* model
,
892 bool ids_reassigned
) {
893 NotifyIfDoneLoading();
896 void BookmarksBridge::BookmarkModelBeingDeleted(BookmarkModel
* model
) {
900 JNIEnv
* env
= AttachCurrentThread();
901 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
904 Java_BookmarksBridge_bookmarkModelDeleted(env
, obj
.obj());
907 void BookmarksBridge::BookmarkNodeMoved(BookmarkModel
* model
,
908 const BookmarkNode
* old_parent
,
910 const BookmarkNode
* new_parent
,
915 JNIEnv
* env
= AttachCurrentThread();
916 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
919 Java_BookmarksBridge_bookmarkNodeMoved(
922 CreateJavaBookmark(old_parent
).obj(),
924 CreateJavaBookmark(new_parent
).obj(),
928 void BookmarksBridge::BookmarkNodeAdded(BookmarkModel
* model
,
929 const BookmarkNode
* parent
,
934 JNIEnv
* env
= AttachCurrentThread();
935 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
938 Java_BookmarksBridge_bookmarkNodeAdded(
941 CreateJavaBookmark(parent
).obj(),
945 void BookmarksBridge::BookmarkNodeRemoved(BookmarkModel
* model
,
946 const BookmarkNode
* parent
,
948 const BookmarkNode
* node
,
949 const std::set
<GURL
>& removed_urls
) {
953 JNIEnv
* env
= AttachCurrentThread();
954 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
957 Java_BookmarksBridge_bookmarkNodeRemoved(
960 CreateJavaBookmark(parent
).obj(),
962 CreateJavaBookmark(node
).obj());
965 void BookmarksBridge::BookmarkAllUserNodesRemoved(
966 BookmarkModel
* model
,
967 const std::set
<GURL
>& removed_urls
) {
971 JNIEnv
* env
= AttachCurrentThread();
972 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
975 Java_BookmarksBridge_bookmarkAllUserNodesRemoved(env
, obj
.obj());
978 void BookmarksBridge::BookmarkNodeChanged(BookmarkModel
* model
,
979 const BookmarkNode
* node
) {
983 JNIEnv
* env
= AttachCurrentThread();
984 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
987 Java_BookmarksBridge_bookmarkNodeChanged(
990 CreateJavaBookmark(node
).obj());
993 void BookmarksBridge::BookmarkNodeChildrenReordered(BookmarkModel
* model
,
994 const BookmarkNode
* node
) {
998 JNIEnv
* env
= AttachCurrentThread();
999 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
1002 Java_BookmarksBridge_bookmarkNodeChildrenReordered(
1005 CreateJavaBookmark(node
).obj());
1008 void BookmarksBridge::ExtensiveBookmarkChangesBeginning(BookmarkModel
* model
) {
1012 JNIEnv
* env
= AttachCurrentThread();
1013 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
1016 Java_BookmarksBridge_extensiveBookmarkChangesBeginning(env
, obj
.obj());
1019 void BookmarksBridge::ExtensiveBookmarkChangesEnded(BookmarkModel
* model
) {
1023 JNIEnv
* env
= AttachCurrentThread();
1024 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
1027 Java_BookmarksBridge_extensiveBookmarkChangesEnded(env
, obj
.obj());
1030 void BookmarksBridge::PartnerShimChanged(PartnerBookmarksShim
* shim
) {
1034 BookmarkModelChanged();
1037 void BookmarksBridge::PartnerShimLoaded(PartnerBookmarksShim
* shim
) {
1038 NotifyIfDoneLoading();
1041 void BookmarksBridge::ShimBeingDeleted(PartnerBookmarksShim
* shim
) {
1042 partner_bookmarks_shim_
= NULL
;