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/managed_bookmark_service_factory.h"
14 #include "chrome/browser/profiles/incognito_helpers.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/profiles/profile_android.h"
17 #include "chrome/browser/signin/signin_manager_factory.h"
18 #include "chrome/browser/undo/bookmark_undo_service_factory.h"
19 #include "chrome/common/pref_names.h"
20 #include "components/bookmarks/browser/bookmark_match.h"
21 #include "components/bookmarks/browser/bookmark_model.h"
22 #include "components/bookmarks/browser/bookmark_utils.h"
23 #include "components/bookmarks/browser/scoped_group_bookmark_actions.h"
24 #include "components/bookmarks/common/android/bookmark_type.h"
25 #include "components/bookmarks/managed/managed_bookmark_service.h"
26 #include "components/enhanced_bookmarks/enhanced_bookmark_features.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
,
138 const JavaParamRef
<jobject
>& obj
,
139 const JavaParamRef
<jobject
>& j_profile
) {
140 BookmarksBridge
* delegate
= new BookmarksBridge(env
, obj
, j_profile
);
141 return reinterpret_cast<intptr_t>(delegate
);
144 static jboolean
IsEnhancedBookmarksFeatureEnabled(
146 const JavaParamRef
<jclass
>& clazz
) {
147 return enhanced_bookmarks::IsEnhancedBookmarksEnabled();
150 jboolean
BookmarksBridge::IsEditBookmarksEnabled(JNIEnv
* env
, jobject obj
) {
151 return IsEditBookmarksEnabled();
154 void BookmarksBridge::LoadEmptyPartnerBookmarkShimForTesting(JNIEnv
* env
,
156 if (partner_bookmarks_shim_
->IsLoaded())
158 partner_bookmarks_shim_
->SetPartnerBookmarksRoot(
159 new BookmarkPermanentNode(0));
160 DCHECK(partner_bookmarks_shim_
->IsLoaded());
163 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetBookmarkByID(JNIEnv
* env
,
168 const BookmarkNode
* node
= GetNodeByID(id
, type
);
169 return node
? CreateJavaBookmark(node
) : ScopedJavaLocalRef
<jobject
>();
172 bool BookmarksBridge::IsDoingExtensiveChanges(JNIEnv
* env
, jobject obj
) {
173 return bookmark_model_
->IsDoingExtensiveChanges();
176 void BookmarksBridge::GetPermanentNodeIDs(JNIEnv
* env
,
178 jobject j_result_obj
) {
179 // TODO(kkimlabs): Remove this function.
182 base::StackVector
<const BookmarkNode
*, 8> permanent_nodes
;
184 // Save all the permanent nodes.
185 const BookmarkNode
* root_node
= bookmark_model_
->root_node();
186 permanent_nodes
->push_back(root_node
);
187 for (int i
= 0; i
< root_node
->child_count(); ++i
) {
188 permanent_nodes
->push_back(root_node
->GetChild(i
));
190 permanent_nodes
->push_back(
191 partner_bookmarks_shim_
->GetPartnerBookmarksRoot());
193 // Write the permanent nodes to |j_result_obj|.
194 for (base::StackVector
<const BookmarkNode
*, 8>::ContainerType::const_iterator
195 it
= permanent_nodes
->begin();
196 it
!= permanent_nodes
->end();
199 Java_BookmarksBridge_addToBookmarkIdList(
200 env
, j_result_obj
, (*it
)->id(), GetBookmarkType(*it
));
205 void BookmarksBridge::GetTopLevelFolderParentIDs(JNIEnv
* env
,
207 jobject j_result_obj
) {
208 Java_BookmarksBridge_addToBookmarkIdList(
209 env
, j_result_obj
, bookmark_model_
->root_node()->id(),
210 GetBookmarkType(bookmark_model_
->root_node()));
213 void BookmarksBridge::GetTopLevelFolderIDs(JNIEnv
* env
,
215 jboolean get_special
,
217 jobject j_result_obj
) {
219 std::vector
<const BookmarkNode
*> top_level_folders
;
222 if (managed_bookmark_service_
->managed_node() &&
223 managed_bookmark_service_
->managed_node()->child_count() > 0) {
224 top_level_folders
.push_back(managed_bookmark_service_
->managed_node());
226 if (managed_bookmark_service_
->supervised_node() &&
227 managed_bookmark_service_
->supervised_node()->child_count() > 0) {
228 top_level_folders
.push_back(managed_bookmark_service_
->supervised_node());
230 if (partner_bookmarks_shim_
->HasPartnerBookmarks()
231 && IsReachable(partner_bookmarks_shim_
->GetPartnerBookmarksRoot())) {
232 top_level_folders
.push_back(
233 partner_bookmarks_shim_
->GetPartnerBookmarksRoot());
236 std::size_t special_count
= top_level_folders
.size();
239 DCHECK_EQ(bookmark_model_
->root_node()->child_count(), 5);
241 const BookmarkNode
* mobile_node
= bookmark_model_
->mobile_node();
242 for (int i
= 0; i
< mobile_node
->child_count(); ++i
) {
243 const BookmarkNode
* node
= mobile_node
->GetChild(i
);
244 if (node
->is_folder()) {
245 top_level_folders
.push_back(node
);
249 const BookmarkNode
* bookmark_bar_node
=
250 bookmark_model_
->bookmark_bar_node();
251 for (int i
= 0; i
< bookmark_bar_node
->child_count(); ++i
) {
252 const BookmarkNode
* node
= bookmark_bar_node
->GetChild(i
);
253 if (node
->is_folder()) {
254 top_level_folders
.push_back(node
);
258 const BookmarkNode
* other_node
= bookmark_model_
->other_node();
259 for (int i
= 0; i
< other_node
->child_count(); ++i
) {
260 const BookmarkNode
* node
= other_node
->GetChild(i
);
261 if (node
->is_folder()) {
262 top_level_folders
.push_back(node
);
266 scoped_ptr
<icu::Collator
> collator
= GetICUCollator();
267 std::stable_sort(top_level_folders
.begin() + special_count
,
268 top_level_folders
.end(),
269 BookmarkTitleComparer(this, collator
.get()));
272 for (std::vector
<const BookmarkNode
*>::const_iterator it
=
273 top_level_folders
.begin(); it
!= top_level_folders
.end(); ++it
) {
274 Java_BookmarksBridge_addToBookmarkIdList(env
,
277 GetBookmarkType(*it
));
281 void BookmarksBridge::GetAllFoldersWithDepths(JNIEnv
* env
,
283 jobject j_folders_obj
,
284 jobject j_depths_obj
) {
287 scoped_ptr
<icu::Collator
> collator
= GetICUCollator();
289 // Vector to temporarily contain all child bookmarks at same level for sorting
290 std::vector
<const BookmarkNode
*> bookmarkList
;
292 // Stack for Depth-First Search of bookmark model. It stores nodes and their
294 std::stack
<std::pair
<const BookmarkNode
*, int> > stk
;
296 bookmarkList
.push_back(bookmark_model_
->mobile_node());
297 bookmarkList
.push_back(bookmark_model_
->bookmark_bar_node());
298 bookmarkList
.push_back(bookmark_model_
->other_node());
300 // Push all sorted top folders in stack and give them depth of 0.
301 // Note the order to push folders to stack should be opposite to the order in
303 for (std::vector
<const BookmarkNode
*>::reverse_iterator it
=
304 bookmarkList
.rbegin();
305 it
!= bookmarkList
.rend();
307 stk
.push(std::make_pair(*it
, 0));
310 while (!stk
.empty()) {
311 const BookmarkNode
* node
= stk
.top().first
;
312 int depth
= stk
.top().second
;
314 Java_BookmarksBridge_addToBookmarkIdListWithDepth(env
,
317 GetBookmarkType(node
),
320 bookmarkList
.clear();
321 for (int i
= 0; i
< node
->child_count(); ++i
) {
322 const BookmarkNode
* child
= node
->GetChild(i
);
323 if (child
->is_folder() &&
324 managed_bookmark_service_
->CanBeEditedByUser(child
)) {
325 bookmarkList
.push_back(node
->GetChild(i
));
328 std::stable_sort(bookmarkList
.begin(),
330 BookmarkTitleComparer(this, collator
.get()));
331 for (std::vector
<const BookmarkNode
*>::reverse_iterator it
=
332 bookmarkList
.rbegin();
333 it
!= bookmarkList
.rend();
335 stk
.push(std::make_pair(*it
, depth
+ 1));
340 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetRootFolderId(JNIEnv
* env
,
342 const BookmarkNode
* root_node
= bookmark_model_
->root_node();
343 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
344 JavaBookmarkIdCreateBookmarkId(
345 env
, root_node
->id(), GetBookmarkType(root_node
));
346 return folder_id_obj
;
349 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetMobileFolderId(JNIEnv
* env
,
351 const BookmarkNode
* mobile_node
= bookmark_model_
->mobile_node();
352 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
353 JavaBookmarkIdCreateBookmarkId(
354 env
, mobile_node
->id(), GetBookmarkType(mobile_node
));
355 return folder_id_obj
;
358 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetOtherFolderId(JNIEnv
* env
,
360 const BookmarkNode
* other_node
= bookmark_model_
->other_node();
361 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
362 JavaBookmarkIdCreateBookmarkId(
363 env
, other_node
->id(), GetBookmarkType(other_node
));
364 return folder_id_obj
;
367 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetDesktopFolderId(JNIEnv
* env
,
369 const BookmarkNode
* desktop_node
= bookmark_model_
->bookmark_bar_node();
370 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
371 JavaBookmarkIdCreateBookmarkId(
372 env
, desktop_node
->id(), GetBookmarkType(desktop_node
));
373 return folder_id_obj
;
376 void BookmarksBridge::GetChildIDs(JNIEnv
* env
,
380 jboolean get_folders
,
381 jboolean get_bookmarks
,
382 jobject j_result_obj
) {
385 const BookmarkNode
* parent
= GetNodeByID(id
, type
);
386 if (!parent
->is_folder() || !IsReachable(parent
))
389 // Get the folder contents
390 for (int i
= 0; i
< parent
->child_count(); ++i
) {
391 const BookmarkNode
* child
= parent
->GetChild(i
);
392 if (!IsFolderAvailable(child
) || !IsReachable(child
))
395 if ((child
->is_folder() && get_folders
) ||
396 (!child
->is_folder() && get_bookmarks
)) {
397 Java_BookmarksBridge_addToBookmarkIdList(
398 env
, j_result_obj
, child
->id(), GetBookmarkType(child
));
402 // Partner bookmark root node is under mobile node.
403 if (parent
== bookmark_model_
->mobile_node() && get_folders
&&
404 partner_bookmarks_shim_
->HasPartnerBookmarks() &&
405 IsReachable(partner_bookmarks_shim_
->GetPartnerBookmarksRoot())) {
406 Java_BookmarksBridge_addToBookmarkIdList(
409 partner_bookmarks_shim_
->GetPartnerBookmarksRoot()->id(),
410 BookmarkType::BOOKMARK_TYPE_PARTNER
);
414 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetChildAt(JNIEnv
* env
,
421 const BookmarkNode
* parent
= GetNodeByID(id
, type
);
423 const BookmarkNode
* child
= parent
->GetChild(index
);
424 return JavaBookmarkIdCreateBookmarkId(
425 env
, child
->id(), GetBookmarkType(child
));
428 void BookmarksBridge::GetAllBookmarkIDsOrderedByCreationDate(
431 jobject j_result_obj
) {
433 std::list
<const BookmarkNode
*> folders
;
434 std::vector
<const BookmarkNode
*> result
;
435 folders
.push_back(bookmark_model_
->root_node());
437 for (std::list
<const BookmarkNode
*>::iterator folder_iter
= folders
.begin();
438 folder_iter
!= folders
.end(); ++folder_iter
) {
439 if (*folder_iter
== NULL
)
442 std::list
<const BookmarkNode
*>::iterator insert_iter
= folder_iter
;
445 for (int i
= 0; i
< (*folder_iter
)->child_count(); ++i
) {
446 const BookmarkNode
* child
= (*folder_iter
)->GetChild(i
);
447 if (!IsReachable(child
) ||
448 bookmarks::IsDescendantOf(
449 child
, managed_bookmark_service_
->managed_node()) ||
450 bookmarks::IsDescendantOf(
451 child
, managed_bookmark_service_
->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
,
509 const BookmarkNode
* node
= GetNodeByID(id
, type
);
514 if (type
== BookmarkType::BOOKMARK_TYPE_NORMAL
) {
517 DCHECK(type
== BookmarkType::BOOKMARK_TYPE_PARTNER
);
518 return partner_bookmarks_shim_
->IsReachable(node
);
522 void BookmarksBridge::GetBookmarksForFolder(JNIEnv
* env
,
524 jobject j_folder_id_obj
,
525 jobject j_callback_obj
,
526 jobject j_result_obj
) {
528 long folder_id
= JavaBookmarkIdGetId(env
, j_folder_id_obj
);
529 int type
= JavaBookmarkIdGetType(env
, j_folder_id_obj
);
530 const BookmarkNode
* folder
= GetFolderWithFallback(folder_id
, type
);
532 if (!folder
->is_folder() || !IsReachable(folder
))
535 // Recreate the java bookmarkId object due to fallback.
536 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
537 JavaBookmarkIdCreateBookmarkId(
538 env
, folder
->id(), GetBookmarkType(folder
));
539 j_folder_id_obj
= folder_id_obj
.obj();
541 // Get the folder contents.
542 for (int i
= 0; i
< folder
->child_count(); ++i
) {
543 const BookmarkNode
* node
= folder
->GetChild(i
);
544 if (!IsFolderAvailable(node
))
546 ExtractBookmarkNodeInformation(node
, j_result_obj
);
549 if (folder
== bookmark_model_
->mobile_node() &&
550 partner_bookmarks_shim_
->HasPartnerBookmarks()) {
551 ExtractBookmarkNodeInformation(
552 partner_bookmarks_shim_
->GetPartnerBookmarksRoot(),
556 if (j_callback_obj
) {
557 Java_BookmarksCallback_onBookmarksAvailable(
558 env
, j_callback_obj
, j_folder_id_obj
, j_result_obj
);
562 jboolean
BookmarksBridge::IsFolderVisible(JNIEnv
* env
,
566 if (type
== BookmarkType::BOOKMARK_TYPE_NORMAL
) {
567 const BookmarkNode
* node
= bookmarks::GetBookmarkNodeByID(
568 bookmark_model_
, static_cast<int64
>(id
));
569 return node
->IsVisible();
570 } else if (type
== BookmarkType::BOOKMARK_TYPE_PARTNER
) {
571 const BookmarkNode
* node
= partner_bookmarks_shim_
->GetNodeByID(
572 static_cast<long>(id
));
573 return partner_bookmarks_shim_
->IsReachable(node
);
580 void BookmarksBridge::GetCurrentFolderHierarchy(JNIEnv
* env
,
582 jobject j_folder_id_obj
,
583 jobject j_callback_obj
,
584 jobject j_result_obj
) {
586 long folder_id
= JavaBookmarkIdGetId(env
, j_folder_id_obj
);
587 int type
= JavaBookmarkIdGetType(env
, j_folder_id_obj
);
588 const BookmarkNode
* folder
= GetFolderWithFallback(folder_id
, type
);
590 if (!folder
->is_folder() || !IsReachable(folder
))
593 // Recreate the java bookmarkId object due to fallback.
594 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
595 JavaBookmarkIdCreateBookmarkId(
596 env
, folder
->id(), GetBookmarkType(folder
));
597 j_folder_id_obj
= folder_id_obj
.obj();
599 // Get the folder hierarchy.
600 const BookmarkNode
* node
= folder
;
602 ExtractBookmarkNodeInformation(node
, j_result_obj
);
603 node
= GetParentNode(node
);
606 Java_BookmarksCallback_onBookmarksFolderHierarchyAvailable(
607 env
, j_callback_obj
, j_folder_id_obj
, j_result_obj
);
610 void BookmarksBridge::SearchBookmarks(JNIEnv
* env
,
615 DCHECK(bookmark_model_
->loaded());
617 std::vector
<bookmarks::BookmarkMatch
> results
;
618 bookmark_model_
->GetBookmarksMatching(
619 base::android::ConvertJavaStringToUTF16(env
, j_query
),
621 query_parser::MatchingAlgorithm::ALWAYS_PREFIX_SEARCH
,
623 for (const bookmarks::BookmarkMatch
& match
: results
) {
624 const BookmarkNode
* node
= match
.node
;
626 std::vector
<int> title_match_start_positions
;
627 std::vector
<int> title_match_end_positions
;
628 for (auto position
: match
.title_match_positions
) {
629 title_match_start_positions
.push_back(position
.first
);
630 title_match_end_positions
.push_back(position
.second
);
633 std::vector
<int> url_match_start_positions
;
634 std::vector
<int> url_match_end_positions
;
635 for (auto position
: match
.url_match_positions
) {
636 url_match_start_positions
.push_back(position
.first
);
637 url_match_end_positions
.push_back(position
.second
);
640 Java_BookmarksBridge_addToBookmarkMatchList(
641 env
, j_list
, node
->id(), node
->type(),
642 ToJavaIntArray(env
, title_match_start_positions
).obj(),
643 ToJavaIntArray(env
, title_match_end_positions
).obj(),
644 ToJavaIntArray(env
, url_match_start_positions
).obj(),
645 ToJavaIntArray(env
, url_match_end_positions
).obj());
649 ScopedJavaLocalRef
<jobject
> BookmarksBridge::AddFolder(JNIEnv
* env
,
651 jobject j_parent_id_obj
,
655 long bookmark_id
= JavaBookmarkIdGetId(env
, j_parent_id_obj
);
656 int type
= JavaBookmarkIdGetType(env
, j_parent_id_obj
);
657 const BookmarkNode
* parent
= GetNodeByID(bookmark_id
, type
);
659 const BookmarkNode
* new_node
= bookmark_model_
->AddFolder(
660 parent
, index
, base::android::ConvertJavaStringToUTF16(env
, j_title
));
663 return ScopedJavaLocalRef
<jobject
>();
665 ScopedJavaLocalRef
<jobject
> new_java_obj
=
666 JavaBookmarkIdCreateBookmarkId(
667 env
, new_node
->id(), GetBookmarkType(new_node
));
671 void BookmarksBridge::DeleteBookmark(JNIEnv
* env
,
673 jobject j_bookmark_id_obj
) {
674 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
677 long bookmark_id
= JavaBookmarkIdGetId(env
, j_bookmark_id_obj
);
678 int type
= JavaBookmarkIdGetType(env
, j_bookmark_id_obj
);
679 const BookmarkNode
* node
= GetNodeByID(bookmark_id
, type
);
680 if (!IsEditable(node
)) {
685 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
686 partner_bookmarks_shim_
->RemoveBookmark(node
);
688 bookmark_model_
->Remove(node
);
691 void BookmarksBridge::MoveBookmark(JNIEnv
* env
,
693 jobject j_bookmark_id_obj
,
694 jobject j_parent_id_obj
,
696 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
699 long bookmark_id
= JavaBookmarkIdGetId(env
, j_bookmark_id_obj
);
700 int type
= JavaBookmarkIdGetType(env
, j_bookmark_id_obj
);
701 const BookmarkNode
* node
= GetNodeByID(bookmark_id
, type
);
702 if (!IsEditable(node
)) {
706 bookmark_id
= JavaBookmarkIdGetId(env
, j_parent_id_obj
);
707 type
= JavaBookmarkIdGetType(env
, j_parent_id_obj
);
708 const BookmarkNode
* new_parent_node
= GetNodeByID(bookmark_id
, type
);
709 bookmark_model_
->Move(node
, new_parent_node
, index
);
712 ScopedJavaLocalRef
<jobject
> BookmarksBridge::AddBookmark(
715 jobject j_parent_id_obj
,
720 long bookmark_id
= JavaBookmarkIdGetId(env
, j_parent_id_obj
);
721 int type
= JavaBookmarkIdGetType(env
, j_parent_id_obj
);
722 const BookmarkNode
* parent
= GetNodeByID(bookmark_id
, type
);
724 const BookmarkNode
* new_node
= bookmark_model_
->AddURL(
727 base::android::ConvertJavaStringToUTF16(env
, j_title
),
728 GURL(base::android::ConvertJavaStringToUTF16(env
, j_url
)));
731 return ScopedJavaLocalRef
<jobject
>();
733 ScopedJavaLocalRef
<jobject
> new_java_obj
=
734 JavaBookmarkIdCreateBookmarkId(
735 env
, new_node
->id(), GetBookmarkType(new_node
));
739 void BookmarksBridge::Undo(JNIEnv
* env
, jobject obj
) {
740 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
742 BookmarkUndoService
* undo_service
=
743 BookmarkUndoServiceFactory::GetForProfile(profile_
);
744 UndoManager
* undo_manager
= undo_service
->undo_manager();
745 undo_manager
->Undo();
748 void BookmarksBridge::StartGroupingUndos(JNIEnv
* env
, jobject obj
) {
749 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
751 DCHECK(!grouped_bookmark_actions_
.get()); // shouldn't have started already
752 grouped_bookmark_actions_
.reset(
753 new bookmarks::ScopedGroupBookmarkActions(bookmark_model_
));
756 void BookmarksBridge::EndGroupingUndos(JNIEnv
* env
, jobject obj
) {
757 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
759 DCHECK(grouped_bookmark_actions_
.get()); // should only call after start
760 grouped_bookmark_actions_
.reset();
763 base::string16
BookmarksBridge::GetTitle(const BookmarkNode
* node
) const {
764 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
765 return partner_bookmarks_shim_
->GetTitle(node
);
767 if (node
== bookmark_model_
->bookmark_bar_node()
768 && enhanced_bookmarks::IsEnhancedBookmarksEnabled()) {
769 return l10n_util::GetStringUTF16(IDS_ENHANCED_BOOKMARK_BAR_FOLDER_NAME
);
772 return node
->GetTitle();
775 ScopedJavaLocalRef
<jobject
> BookmarksBridge::CreateJavaBookmark(
776 const BookmarkNode
* node
) {
777 JNIEnv
* env
= AttachCurrentThread();
779 const BookmarkNode
* parent
= GetParentNode(node
);
780 int64 parent_id
= parent
? parent
->id() : -1;
784 url
= node
->url().spec();
786 return Java_BookmarksBridge_createBookmarkItem(
789 GetBookmarkType(node
),
790 ConvertUTF16ToJavaString(env
, GetTitle(node
)).obj(),
791 ConvertUTF8ToJavaString(env
, url
).obj(),
794 GetBookmarkType(parent
),
799 void BookmarksBridge::ExtractBookmarkNodeInformation(const BookmarkNode
* node
,
800 jobject j_result_obj
) {
801 JNIEnv
* env
= AttachCurrentThread();
802 if (!IsReachable(node
))
804 Java_BookmarksBridge_addToList(
805 env
, j_result_obj
, CreateJavaBookmark(node
).obj());
808 const BookmarkNode
* BookmarksBridge::GetNodeByID(long node_id
, int type
) {
809 const BookmarkNode
* node
;
810 if (type
== BookmarkType::BOOKMARK_TYPE_PARTNER
) {
811 node
= partner_bookmarks_shim_
->GetNodeByID(
812 static_cast<int64
>(node_id
));
814 node
= bookmarks::GetBookmarkNodeByID(bookmark_model_
,
815 static_cast<int64
>(node_id
));
820 const BookmarkNode
* BookmarksBridge::GetFolderWithFallback(long folder_id
,
822 const BookmarkNode
* folder
= GetNodeByID(folder_id
, type
);
823 if (!folder
|| folder
->type() == BookmarkNode::URL
||
824 !IsFolderAvailable(folder
)) {
825 if (!managed_bookmark_service_
->managed_node()->empty())
826 folder
= managed_bookmark_service_
->managed_node();
828 folder
= bookmark_model_
->mobile_node();
833 bool BookmarksBridge::IsEditBookmarksEnabled() const {
834 return profile_
->GetPrefs()->GetBoolean(
835 bookmarks::prefs::kEditBookmarksEnabled
);
838 bool BookmarksBridge::IsEditable(const BookmarkNode
* node
) const {
839 if (!node
|| (node
->type() != BookmarkNode::FOLDER
&&
840 node
->type() != BookmarkNode::URL
)) {
843 if (!IsEditBookmarksEnabled())
845 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
846 return partner_bookmarks_shim_
->IsEditable(node
);
847 return managed_bookmark_service_
->CanBeEditedByUser(node
);
850 bool BookmarksBridge::IsManaged(const BookmarkNode
* node
) const {
851 return bookmarks::IsDescendantOf(node
,
852 managed_bookmark_service_
->managed_node());
855 const BookmarkNode
* BookmarksBridge::GetParentNode(const BookmarkNode
* node
) {
857 if (node
== partner_bookmarks_shim_
->GetPartnerBookmarksRoot()) {
858 return bookmark_model_
->mobile_node();
860 return node
->parent();
864 int BookmarksBridge::GetBookmarkType(const BookmarkNode
* node
) {
865 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
866 return BookmarkType::BOOKMARK_TYPE_PARTNER
;
868 return BookmarkType::BOOKMARK_TYPE_NORMAL
;
871 bool BookmarksBridge::IsReachable(const BookmarkNode
* node
) const {
872 if (!partner_bookmarks_shim_
->IsPartnerBookmark(node
))
874 return partner_bookmarks_shim_
->IsReachable(node
);
877 bool BookmarksBridge::IsLoaded() const {
878 return (bookmark_model_
->loaded() && partner_bookmarks_shim_
->IsLoaded());
881 bool BookmarksBridge::IsFolderAvailable(
882 const BookmarkNode
* folder
) const {
883 // The managed bookmarks folder is not shown if there are no bookmarks
884 // configured via policy.
885 if (folder
== managed_bookmark_service_
->managed_node() && folder
->empty())
887 // Similarly, the supervised bookmarks folder is not shown if there are no
888 // bookmarks configured by the custodian.
889 if (folder
== managed_bookmark_service_
->supervised_node() && folder
->empty())
892 SigninManager
* signin
= SigninManagerFactory::GetForProfile(
893 profile_
->GetOriginalProfile());
894 return (folder
->type() != BookmarkNode::BOOKMARK_BAR
&&
895 folder
->type() != BookmarkNode::OTHER_NODE
) ||
896 (signin
&& signin
->IsAuthenticated());
899 void BookmarksBridge::NotifyIfDoneLoading() {
902 JNIEnv
* env
= AttachCurrentThread();
903 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
906 Java_BookmarksBridge_bookmarkModelLoaded(env
, obj
.obj());
909 // ------------- Observer-related methods ------------- //
911 void BookmarksBridge::BookmarkModelChanged() {
915 // Called when there are changes to the bookmark model. It is most
916 // likely changes to the partner bookmarks.
917 JNIEnv
* env
= AttachCurrentThread();
918 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
921 Java_BookmarksBridge_bookmarkModelChanged(env
, obj
.obj());
924 void BookmarksBridge::BookmarkModelLoaded(BookmarkModel
* model
,
925 bool ids_reassigned
) {
926 NotifyIfDoneLoading();
929 void BookmarksBridge::BookmarkModelBeingDeleted(BookmarkModel
* model
) {
933 JNIEnv
* env
= AttachCurrentThread();
934 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
937 Java_BookmarksBridge_bookmarkModelDeleted(env
, obj
.obj());
940 void BookmarksBridge::BookmarkNodeMoved(BookmarkModel
* model
,
941 const BookmarkNode
* old_parent
,
943 const BookmarkNode
* new_parent
,
948 JNIEnv
* env
= AttachCurrentThread();
949 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
952 Java_BookmarksBridge_bookmarkNodeMoved(
955 CreateJavaBookmark(old_parent
).obj(),
957 CreateJavaBookmark(new_parent
).obj(),
961 void BookmarksBridge::BookmarkNodeAdded(BookmarkModel
* model
,
962 const BookmarkNode
* parent
,
967 JNIEnv
* env
= AttachCurrentThread();
968 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
971 Java_BookmarksBridge_bookmarkNodeAdded(
974 CreateJavaBookmark(parent
).obj(),
978 void BookmarksBridge::BookmarkNodeRemoved(BookmarkModel
* model
,
979 const BookmarkNode
* parent
,
981 const BookmarkNode
* node
,
982 const std::set
<GURL
>& removed_urls
) {
986 JNIEnv
* env
= AttachCurrentThread();
987 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
990 Java_BookmarksBridge_bookmarkNodeRemoved(
993 CreateJavaBookmark(parent
).obj(),
995 CreateJavaBookmark(node
).obj());
998 void BookmarksBridge::BookmarkAllUserNodesRemoved(
999 BookmarkModel
* model
,
1000 const std::set
<GURL
>& removed_urls
) {
1004 JNIEnv
* env
= AttachCurrentThread();
1005 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
1008 Java_BookmarksBridge_bookmarkAllUserNodesRemoved(env
, obj
.obj());
1011 void BookmarksBridge::BookmarkNodeChanged(BookmarkModel
* model
,
1012 const BookmarkNode
* node
) {
1016 JNIEnv
* env
= AttachCurrentThread();
1017 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
1020 Java_BookmarksBridge_bookmarkNodeChanged(
1023 CreateJavaBookmark(node
).obj());
1026 void BookmarksBridge::BookmarkNodeChildrenReordered(BookmarkModel
* model
,
1027 const BookmarkNode
* node
) {
1031 JNIEnv
* env
= AttachCurrentThread();
1032 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
1035 Java_BookmarksBridge_bookmarkNodeChildrenReordered(
1038 CreateJavaBookmark(node
).obj());
1041 void BookmarksBridge::ExtensiveBookmarkChangesBeginning(BookmarkModel
* model
) {
1045 JNIEnv
* env
= AttachCurrentThread();
1046 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
1049 Java_BookmarksBridge_extensiveBookmarkChangesBeginning(env
, obj
.obj());
1052 void BookmarksBridge::ExtensiveBookmarkChangesEnded(BookmarkModel
* model
) {
1056 JNIEnv
* env
= AttachCurrentThread();
1057 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
1060 Java_BookmarksBridge_extensiveBookmarkChangesEnded(env
, obj
.obj());
1063 void BookmarksBridge::PartnerShimChanged(PartnerBookmarksShim
* shim
) {
1067 BookmarkModelChanged();
1070 void BookmarksBridge::PartnerShimLoaded(PartnerBookmarksShim
* shim
) {
1071 NotifyIfDoneLoading();
1074 void BookmarksBridge::ShimBeingDeleted(PartnerBookmarksShim
* shim
) {
1075 partner_bookmarks_shim_
= NULL
;