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
, 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
,
144 return enhanced_bookmarks::IsEnhancedBookmarksEnabled();
147 jboolean
BookmarksBridge::IsEditBookmarksEnabled(JNIEnv
* env
, jobject obj
) {
148 return IsEditBookmarksEnabled();
151 void BookmarksBridge::LoadEmptyPartnerBookmarkShimForTesting(JNIEnv
* env
,
153 if (partner_bookmarks_shim_
->IsLoaded())
155 partner_bookmarks_shim_
->SetPartnerBookmarksRoot(
156 new BookmarkPermanentNode(0));
157 DCHECK(partner_bookmarks_shim_
->IsLoaded());
160 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetBookmarkByID(JNIEnv
* env
,
165 const BookmarkNode
* node
= GetNodeByID(id
, type
);
166 return node
? CreateJavaBookmark(node
) : ScopedJavaLocalRef
<jobject
>();
169 bool BookmarksBridge::IsDoingExtensiveChanges(JNIEnv
* env
, jobject obj
) {
170 return bookmark_model_
->IsDoingExtensiveChanges();
173 void BookmarksBridge::GetPermanentNodeIDs(JNIEnv
* env
,
175 jobject j_result_obj
) {
176 // TODO(kkimlabs): Remove this function.
179 base::StackVector
<const BookmarkNode
*, 8> permanent_nodes
;
181 // Save all the permanent nodes.
182 const BookmarkNode
* root_node
= bookmark_model_
->root_node();
183 permanent_nodes
->push_back(root_node
);
184 for (int i
= 0; i
< root_node
->child_count(); ++i
) {
185 permanent_nodes
->push_back(root_node
->GetChild(i
));
187 permanent_nodes
->push_back(
188 partner_bookmarks_shim_
->GetPartnerBookmarksRoot());
190 // Write the permanent nodes to |j_result_obj|.
191 for (base::StackVector
<const BookmarkNode
*, 8>::ContainerType::const_iterator
192 it
= permanent_nodes
->begin();
193 it
!= permanent_nodes
->end();
196 Java_BookmarksBridge_addToBookmarkIdList(
197 env
, j_result_obj
, (*it
)->id(), GetBookmarkType(*it
));
202 void BookmarksBridge::GetTopLevelFolderParentIDs(JNIEnv
* env
,
204 jobject j_result_obj
) {
205 Java_BookmarksBridge_addToBookmarkIdList(
206 env
, j_result_obj
, bookmark_model_
->root_node()->id(),
207 GetBookmarkType(bookmark_model_
->root_node()));
210 void BookmarksBridge::GetTopLevelFolderIDs(JNIEnv
* env
,
212 jboolean get_special
,
214 jobject j_result_obj
) {
216 std::vector
<const BookmarkNode
*> top_level_folders
;
219 if (managed_bookmark_service_
->managed_node() &&
220 managed_bookmark_service_
->managed_node()->child_count() > 0) {
221 top_level_folders
.push_back(managed_bookmark_service_
->managed_node());
223 if (managed_bookmark_service_
->supervised_node() &&
224 managed_bookmark_service_
->supervised_node()->child_count() > 0) {
225 top_level_folders
.push_back(managed_bookmark_service_
->supervised_node());
227 if (partner_bookmarks_shim_
->HasPartnerBookmarks()
228 && IsReachable(partner_bookmarks_shim_
->GetPartnerBookmarksRoot())) {
229 top_level_folders
.push_back(
230 partner_bookmarks_shim_
->GetPartnerBookmarksRoot());
233 std::size_t special_count
= top_level_folders
.size();
236 DCHECK_EQ(bookmark_model_
->root_node()->child_count(), 5);
238 const BookmarkNode
* mobile_node
= bookmark_model_
->mobile_node();
239 for (int i
= 0; i
< mobile_node
->child_count(); ++i
) {
240 const BookmarkNode
* node
= mobile_node
->GetChild(i
);
241 if (node
->is_folder()) {
242 top_level_folders
.push_back(node
);
246 const BookmarkNode
* bookmark_bar_node
=
247 bookmark_model_
->bookmark_bar_node();
248 for (int i
= 0; i
< bookmark_bar_node
->child_count(); ++i
) {
249 const BookmarkNode
* node
= bookmark_bar_node
->GetChild(i
);
250 if (node
->is_folder()) {
251 top_level_folders
.push_back(node
);
255 const BookmarkNode
* other_node
= bookmark_model_
->other_node();
256 for (int i
= 0; i
< other_node
->child_count(); ++i
) {
257 const BookmarkNode
* node
= other_node
->GetChild(i
);
258 if (node
->is_folder()) {
259 top_level_folders
.push_back(node
);
263 scoped_ptr
<icu::Collator
> collator
= GetICUCollator();
264 std::stable_sort(top_level_folders
.begin() + special_count
,
265 top_level_folders
.end(),
266 BookmarkTitleComparer(this, collator
.get()));
269 for (std::vector
<const BookmarkNode
*>::const_iterator it
=
270 top_level_folders
.begin(); it
!= top_level_folders
.end(); ++it
) {
271 Java_BookmarksBridge_addToBookmarkIdList(env
,
274 GetBookmarkType(*it
));
278 void BookmarksBridge::GetAllFoldersWithDepths(JNIEnv
* env
,
280 jobject j_folders_obj
,
281 jobject j_depths_obj
) {
284 scoped_ptr
<icu::Collator
> collator
= GetICUCollator();
286 // Vector to temporarily contain all child bookmarks at same level for sorting
287 std::vector
<const BookmarkNode
*> bookmarkList
;
289 // Stack for Depth-First Search of bookmark model. It stores nodes and their
291 std::stack
<std::pair
<const BookmarkNode
*, int> > stk
;
293 bookmarkList
.push_back(bookmark_model_
->mobile_node());
294 bookmarkList
.push_back(bookmark_model_
->bookmark_bar_node());
295 bookmarkList
.push_back(bookmark_model_
->other_node());
297 // Push all sorted top folders in stack and give them depth of 0.
298 // Note the order to push folders to stack should be opposite to the order in
300 for (std::vector
<const BookmarkNode
*>::reverse_iterator it
=
301 bookmarkList
.rbegin();
302 it
!= bookmarkList
.rend();
304 stk
.push(std::make_pair(*it
, 0));
307 while (!stk
.empty()) {
308 const BookmarkNode
* node
= stk
.top().first
;
309 int depth
= stk
.top().second
;
311 Java_BookmarksBridge_addToBookmarkIdListWithDepth(env
,
314 GetBookmarkType(node
),
317 bookmarkList
.clear();
318 for (int i
= 0; i
< node
->child_count(); ++i
) {
319 const BookmarkNode
* child
= node
->GetChild(i
);
320 if (child
->is_folder() &&
321 managed_bookmark_service_
->CanBeEditedByUser(child
)) {
322 bookmarkList
.push_back(node
->GetChild(i
));
325 std::stable_sort(bookmarkList
.begin(),
327 BookmarkTitleComparer(this, collator
.get()));
328 for (std::vector
<const BookmarkNode
*>::reverse_iterator it
=
329 bookmarkList
.rbegin();
330 it
!= bookmarkList
.rend();
332 stk
.push(std::make_pair(*it
, depth
+ 1));
337 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetRootFolderId(JNIEnv
* env
,
339 const BookmarkNode
* root_node
= bookmark_model_
->root_node();
340 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
341 JavaBookmarkIdCreateBookmarkId(
342 env
, root_node
->id(), GetBookmarkType(root_node
));
343 return folder_id_obj
;
346 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetMobileFolderId(JNIEnv
* env
,
348 const BookmarkNode
* mobile_node
= bookmark_model_
->mobile_node();
349 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
350 JavaBookmarkIdCreateBookmarkId(
351 env
, mobile_node
->id(), GetBookmarkType(mobile_node
));
352 return folder_id_obj
;
355 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetOtherFolderId(JNIEnv
* env
,
357 const BookmarkNode
* other_node
= bookmark_model_
->other_node();
358 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
359 JavaBookmarkIdCreateBookmarkId(
360 env
, other_node
->id(), GetBookmarkType(other_node
));
361 return folder_id_obj
;
364 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetDesktopFolderId(JNIEnv
* env
,
366 const BookmarkNode
* desktop_node
= bookmark_model_
->bookmark_bar_node();
367 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
368 JavaBookmarkIdCreateBookmarkId(
369 env
, desktop_node
->id(), GetBookmarkType(desktop_node
));
370 return folder_id_obj
;
373 void BookmarksBridge::GetChildIDs(JNIEnv
* env
,
377 jboolean get_folders
,
378 jboolean get_bookmarks
,
379 jobject j_result_obj
) {
382 const BookmarkNode
* parent
= GetNodeByID(id
, type
);
383 if (!parent
->is_folder() || !IsReachable(parent
))
386 // Get the folder contents
387 for (int i
= 0; i
< parent
->child_count(); ++i
) {
388 const BookmarkNode
* child
= parent
->GetChild(i
);
389 if (!IsFolderAvailable(child
) || !IsReachable(child
))
392 if ((child
->is_folder() && get_folders
) ||
393 (!child
->is_folder() && get_bookmarks
)) {
394 Java_BookmarksBridge_addToBookmarkIdList(
395 env
, j_result_obj
, child
->id(), GetBookmarkType(child
));
399 // Partner bookmark root node is under mobile node.
400 if (parent
== bookmark_model_
->mobile_node() && get_folders
&&
401 partner_bookmarks_shim_
->HasPartnerBookmarks() &&
402 IsReachable(partner_bookmarks_shim_
->GetPartnerBookmarksRoot())) {
403 Java_BookmarksBridge_addToBookmarkIdList(
406 partner_bookmarks_shim_
->GetPartnerBookmarksRoot()->id(),
407 BookmarkType::BOOKMARK_TYPE_PARTNER
);
411 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetChildAt(JNIEnv
* env
,
418 const BookmarkNode
* parent
= GetNodeByID(id
, type
);
420 const BookmarkNode
* child
= parent
->GetChild(index
);
421 return JavaBookmarkIdCreateBookmarkId(
422 env
, child
->id(), GetBookmarkType(child
));
425 void BookmarksBridge::GetAllBookmarkIDsOrderedByCreationDate(
428 jobject j_result_obj
) {
430 std::list
<const BookmarkNode
*> folders
;
431 std::vector
<const BookmarkNode
*> result
;
432 folders
.push_back(bookmark_model_
->root_node());
434 for (std::list
<const BookmarkNode
*>::iterator folder_iter
= folders
.begin();
435 folder_iter
!= folders
.end(); ++folder_iter
) {
436 if (*folder_iter
== NULL
)
439 std::list
<const BookmarkNode
*>::iterator insert_iter
= folder_iter
;
442 for (int i
= 0; i
< (*folder_iter
)->child_count(); ++i
) {
443 const BookmarkNode
* child
= (*folder_iter
)->GetChild(i
);
444 if (!IsReachable(child
) ||
445 bookmarks::IsDescendantOf(
446 child
, managed_bookmark_service_
->managed_node()) ||
447 bookmarks::IsDescendantOf(
448 child
, managed_bookmark_service_
->supervised_node())) {
452 if (child
->is_folder()) {
453 insert_iter
= folders
.insert(insert_iter
, child
);
455 result
.push_back(child
);
461 result
.begin(), result
.end(), BookmarkNodeCreationTimeCompareFunctor());
463 for (std::vector
<const BookmarkNode
*>::const_iterator iter
= result
.begin();
464 iter
!= result
.end();
466 const BookmarkNode
* bookmark
= *iter
;
467 Java_BookmarksBridge_addToBookmarkIdList(
468 env
, j_result_obj
, bookmark
->id(), GetBookmarkType(bookmark
));
472 void BookmarksBridge::SetBookmarkTitle(JNIEnv
* env
,
478 const BookmarkNode
* bookmark
= GetNodeByID(id
, type
);
479 const base::string16 title
=
480 base::android::ConvertJavaStringToUTF16(env
, j_title
);
482 if (partner_bookmarks_shim_
->IsPartnerBookmark(bookmark
)) {
483 partner_bookmarks_shim_
->RenameBookmark(bookmark
, title
);
485 bookmark_model_
->SetTitle(bookmark
, title
);
489 void BookmarksBridge::SetBookmarkUrl(JNIEnv
* env
,
495 bookmark_model_
->SetURL(
496 GetNodeByID(id
, type
),
497 GURL(base::android::ConvertJavaStringToUTF16(env
, url
)));
500 bool BookmarksBridge::DoesBookmarkExist(JNIEnv
* env
,
506 const BookmarkNode
* node
= GetNodeByID(id
, type
);
511 if (type
== BookmarkType::BOOKMARK_TYPE_NORMAL
) {
514 DCHECK(type
== BookmarkType::BOOKMARK_TYPE_PARTNER
);
515 return partner_bookmarks_shim_
->IsReachable(node
);
519 void BookmarksBridge::GetBookmarksForFolder(JNIEnv
* env
,
521 jobject j_folder_id_obj
,
522 jobject j_callback_obj
,
523 jobject j_result_obj
) {
525 long folder_id
= JavaBookmarkIdGetId(env
, j_folder_id_obj
);
526 int type
= JavaBookmarkIdGetType(env
, j_folder_id_obj
);
527 const BookmarkNode
* folder
= GetFolderWithFallback(folder_id
, type
);
529 if (!folder
->is_folder() || !IsReachable(folder
))
532 // Recreate the java bookmarkId object due to fallback.
533 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
534 JavaBookmarkIdCreateBookmarkId(
535 env
, folder
->id(), GetBookmarkType(folder
));
536 j_folder_id_obj
= folder_id_obj
.obj();
538 // Get the folder contents.
539 for (int i
= 0; i
< folder
->child_count(); ++i
) {
540 const BookmarkNode
* node
= folder
->GetChild(i
);
541 if (!IsFolderAvailable(node
))
543 ExtractBookmarkNodeInformation(node
, j_result_obj
);
546 if (folder
== bookmark_model_
->mobile_node() &&
547 partner_bookmarks_shim_
->HasPartnerBookmarks()) {
548 ExtractBookmarkNodeInformation(
549 partner_bookmarks_shim_
->GetPartnerBookmarksRoot(),
553 if (j_callback_obj
) {
554 Java_BookmarksCallback_onBookmarksAvailable(
555 env
, j_callback_obj
, j_folder_id_obj
, j_result_obj
);
559 jboolean
BookmarksBridge::IsFolderVisible(JNIEnv
* env
,
563 if (type
== BookmarkType::BOOKMARK_TYPE_NORMAL
) {
564 const BookmarkNode
* node
= bookmarks::GetBookmarkNodeByID(
565 bookmark_model_
, static_cast<int64
>(id
));
566 return node
->IsVisible();
567 } else if (type
== BookmarkType::BOOKMARK_TYPE_PARTNER
) {
568 const BookmarkNode
* node
= partner_bookmarks_shim_
->GetNodeByID(
569 static_cast<long>(id
));
570 return partner_bookmarks_shim_
->IsReachable(node
);
577 void BookmarksBridge::GetCurrentFolderHierarchy(JNIEnv
* env
,
579 jobject j_folder_id_obj
,
580 jobject j_callback_obj
,
581 jobject j_result_obj
) {
583 long folder_id
= JavaBookmarkIdGetId(env
, j_folder_id_obj
);
584 int type
= JavaBookmarkIdGetType(env
, j_folder_id_obj
);
585 const BookmarkNode
* folder
= GetFolderWithFallback(folder_id
, type
);
587 if (!folder
->is_folder() || !IsReachable(folder
))
590 // Recreate the java bookmarkId object due to fallback.
591 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
592 JavaBookmarkIdCreateBookmarkId(
593 env
, folder
->id(), GetBookmarkType(folder
));
594 j_folder_id_obj
= folder_id_obj
.obj();
596 // Get the folder hierarchy.
597 const BookmarkNode
* node
= folder
;
599 ExtractBookmarkNodeInformation(node
, j_result_obj
);
600 node
= GetParentNode(node
);
603 Java_BookmarksCallback_onBookmarksFolderHierarchyAvailable(
604 env
, j_callback_obj
, j_folder_id_obj
, j_result_obj
);
607 void BookmarksBridge::SearchBookmarks(JNIEnv
* env
,
612 DCHECK(bookmark_model_
->loaded());
614 std::vector
<bookmarks::BookmarkMatch
> results
;
615 bookmark_model_
->GetBookmarksMatching(
616 base::android::ConvertJavaStringToUTF16(env
, j_query
),
618 query_parser::MatchingAlgorithm::ALWAYS_PREFIX_SEARCH
,
620 for (const bookmarks::BookmarkMatch
& match
: results
) {
621 const BookmarkNode
* node
= match
.node
;
623 std::vector
<int> title_match_start_positions
;
624 std::vector
<int> title_match_end_positions
;
625 for (auto position
: match
.title_match_positions
) {
626 title_match_start_positions
.push_back(position
.first
);
627 title_match_end_positions
.push_back(position
.second
);
630 std::vector
<int> url_match_start_positions
;
631 std::vector
<int> url_match_end_positions
;
632 for (auto position
: match
.url_match_positions
) {
633 url_match_start_positions
.push_back(position
.first
);
634 url_match_end_positions
.push_back(position
.second
);
637 Java_BookmarksBridge_addToBookmarkMatchList(
638 env
, j_list
, node
->id(), node
->type(),
639 ToJavaIntArray(env
, title_match_start_positions
).obj(),
640 ToJavaIntArray(env
, title_match_end_positions
).obj(),
641 ToJavaIntArray(env
, url_match_start_positions
).obj(),
642 ToJavaIntArray(env
, url_match_end_positions
).obj());
646 ScopedJavaLocalRef
<jobject
> BookmarksBridge::AddFolder(JNIEnv
* env
,
648 jobject j_parent_id_obj
,
652 long bookmark_id
= JavaBookmarkIdGetId(env
, j_parent_id_obj
);
653 int type
= JavaBookmarkIdGetType(env
, j_parent_id_obj
);
654 const BookmarkNode
* parent
= GetNodeByID(bookmark_id
, type
);
656 const BookmarkNode
* new_node
= bookmark_model_
->AddFolder(
657 parent
, index
, base::android::ConvertJavaStringToUTF16(env
, j_title
));
660 return ScopedJavaLocalRef
<jobject
>();
662 ScopedJavaLocalRef
<jobject
> new_java_obj
=
663 JavaBookmarkIdCreateBookmarkId(
664 env
, new_node
->id(), GetBookmarkType(new_node
));
668 void BookmarksBridge::DeleteBookmark(JNIEnv
* env
,
670 jobject j_bookmark_id_obj
) {
671 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
674 long bookmark_id
= JavaBookmarkIdGetId(env
, j_bookmark_id_obj
);
675 int type
= JavaBookmarkIdGetType(env
, j_bookmark_id_obj
);
676 const BookmarkNode
* node
= GetNodeByID(bookmark_id
, type
);
677 if (!IsEditable(node
)) {
682 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
683 partner_bookmarks_shim_
->RemoveBookmark(node
);
685 bookmark_model_
->Remove(node
);
688 void BookmarksBridge::MoveBookmark(JNIEnv
* env
,
690 jobject j_bookmark_id_obj
,
691 jobject j_parent_id_obj
,
693 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
696 long bookmark_id
= JavaBookmarkIdGetId(env
, j_bookmark_id_obj
);
697 int type
= JavaBookmarkIdGetType(env
, j_bookmark_id_obj
);
698 const BookmarkNode
* node
= GetNodeByID(bookmark_id
, type
);
699 if (!IsEditable(node
)) {
703 bookmark_id
= JavaBookmarkIdGetId(env
, j_parent_id_obj
);
704 type
= JavaBookmarkIdGetType(env
, j_parent_id_obj
);
705 const BookmarkNode
* new_parent_node
= GetNodeByID(bookmark_id
, type
);
706 bookmark_model_
->Move(node
, new_parent_node
, index
);
709 ScopedJavaLocalRef
<jobject
> BookmarksBridge::AddBookmark(
712 jobject j_parent_id_obj
,
717 long bookmark_id
= JavaBookmarkIdGetId(env
, j_parent_id_obj
);
718 int type
= JavaBookmarkIdGetType(env
, j_parent_id_obj
);
719 const BookmarkNode
* parent
= GetNodeByID(bookmark_id
, type
);
721 const BookmarkNode
* new_node
= bookmark_model_
->AddURL(
724 base::android::ConvertJavaStringToUTF16(env
, j_title
),
725 GURL(base::android::ConvertJavaStringToUTF16(env
, j_url
)));
728 return ScopedJavaLocalRef
<jobject
>();
730 ScopedJavaLocalRef
<jobject
> new_java_obj
=
731 JavaBookmarkIdCreateBookmarkId(
732 env
, new_node
->id(), GetBookmarkType(new_node
));
736 void BookmarksBridge::Undo(JNIEnv
* env
, jobject obj
) {
737 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
739 BookmarkUndoService
* undo_service
=
740 BookmarkUndoServiceFactory::GetForProfile(profile_
);
741 UndoManager
* undo_manager
= undo_service
->undo_manager();
742 undo_manager
->Undo();
745 void BookmarksBridge::StartGroupingUndos(JNIEnv
* env
, jobject obj
) {
746 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
748 DCHECK(!grouped_bookmark_actions_
.get()); // shouldn't have started already
749 grouped_bookmark_actions_
.reset(
750 new bookmarks::ScopedGroupBookmarkActions(bookmark_model_
));
753 void BookmarksBridge::EndGroupingUndos(JNIEnv
* env
, jobject obj
) {
754 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
756 DCHECK(grouped_bookmark_actions_
.get()); // should only call after start
757 grouped_bookmark_actions_
.reset();
760 base::string16
BookmarksBridge::GetTitle(const BookmarkNode
* node
) const {
761 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
762 return partner_bookmarks_shim_
->GetTitle(node
);
764 if (node
== bookmark_model_
->bookmark_bar_node()
765 && enhanced_bookmarks::IsEnhancedBookmarksEnabled()) {
766 return l10n_util::GetStringUTF16(IDS_ENHANCED_BOOKMARK_BAR_FOLDER_NAME
);
769 return node
->GetTitle();
772 ScopedJavaLocalRef
<jobject
> BookmarksBridge::CreateJavaBookmark(
773 const BookmarkNode
* node
) {
774 JNIEnv
* env
= AttachCurrentThread();
776 const BookmarkNode
* parent
= GetParentNode(node
);
777 int64 parent_id
= parent
? parent
->id() : -1;
781 url
= node
->url().spec();
783 return Java_BookmarksBridge_createBookmarkItem(
786 GetBookmarkType(node
),
787 ConvertUTF16ToJavaString(env
, GetTitle(node
)).obj(),
788 ConvertUTF8ToJavaString(env
, url
).obj(),
791 GetBookmarkType(parent
),
796 void BookmarksBridge::ExtractBookmarkNodeInformation(const BookmarkNode
* node
,
797 jobject j_result_obj
) {
798 JNIEnv
* env
= AttachCurrentThread();
799 if (!IsReachable(node
))
801 Java_BookmarksBridge_addToList(
802 env
, j_result_obj
, CreateJavaBookmark(node
).obj());
805 const BookmarkNode
* BookmarksBridge::GetNodeByID(long node_id
, int type
) {
806 const BookmarkNode
* node
;
807 if (type
== BookmarkType::BOOKMARK_TYPE_PARTNER
) {
808 node
= partner_bookmarks_shim_
->GetNodeByID(
809 static_cast<int64
>(node_id
));
811 node
= bookmarks::GetBookmarkNodeByID(bookmark_model_
,
812 static_cast<int64
>(node_id
));
817 const BookmarkNode
* BookmarksBridge::GetFolderWithFallback(long folder_id
,
819 const BookmarkNode
* folder
= GetNodeByID(folder_id
, type
);
820 if (!folder
|| folder
->type() == BookmarkNode::URL
||
821 !IsFolderAvailable(folder
)) {
822 if (!managed_bookmark_service_
->managed_node()->empty())
823 folder
= managed_bookmark_service_
->managed_node();
825 folder
= bookmark_model_
->mobile_node();
830 bool BookmarksBridge::IsEditBookmarksEnabled() const {
831 return profile_
->GetPrefs()->GetBoolean(
832 bookmarks::prefs::kEditBookmarksEnabled
);
835 bool BookmarksBridge::IsEditable(const BookmarkNode
* node
) const {
836 if (!node
|| (node
->type() != BookmarkNode::FOLDER
&&
837 node
->type() != BookmarkNode::URL
)) {
840 if (!IsEditBookmarksEnabled())
842 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
843 return partner_bookmarks_shim_
->IsEditable(node
);
844 return managed_bookmark_service_
->CanBeEditedByUser(node
);
847 bool BookmarksBridge::IsManaged(const BookmarkNode
* node
) const {
848 return bookmarks::IsDescendantOf(node
,
849 managed_bookmark_service_
->managed_node());
852 const BookmarkNode
* BookmarksBridge::GetParentNode(const BookmarkNode
* node
) {
854 if (node
== partner_bookmarks_shim_
->GetPartnerBookmarksRoot()) {
855 return bookmark_model_
->mobile_node();
857 return node
->parent();
861 int BookmarksBridge::GetBookmarkType(const BookmarkNode
* node
) {
862 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
863 return BookmarkType::BOOKMARK_TYPE_PARTNER
;
865 return BookmarkType::BOOKMARK_TYPE_NORMAL
;
868 bool BookmarksBridge::IsReachable(const BookmarkNode
* node
) const {
869 if (!partner_bookmarks_shim_
->IsPartnerBookmark(node
))
871 return partner_bookmarks_shim_
->IsReachable(node
);
874 bool BookmarksBridge::IsLoaded() const {
875 return (bookmark_model_
->loaded() && partner_bookmarks_shim_
->IsLoaded());
878 bool BookmarksBridge::IsFolderAvailable(
879 const BookmarkNode
* folder
) const {
880 // The managed bookmarks folder is not shown if there are no bookmarks
881 // configured via policy.
882 if (folder
== managed_bookmark_service_
->managed_node() && folder
->empty())
884 // Similarly, the supervised bookmarks folder is not shown if there are no
885 // bookmarks configured by the custodian.
886 if (folder
== managed_bookmark_service_
->supervised_node() && folder
->empty())
889 SigninManager
* signin
= SigninManagerFactory::GetForProfile(
890 profile_
->GetOriginalProfile());
891 return (folder
->type() != BookmarkNode::BOOKMARK_BAR
&&
892 folder
->type() != BookmarkNode::OTHER_NODE
) ||
893 (signin
&& signin
->IsAuthenticated());
896 void BookmarksBridge::NotifyIfDoneLoading() {
899 JNIEnv
* env
= AttachCurrentThread();
900 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
903 Java_BookmarksBridge_bookmarkModelLoaded(env
, obj
.obj());
906 // ------------- Observer-related methods ------------- //
908 void BookmarksBridge::BookmarkModelChanged() {
912 // Called when there are changes to the bookmark model. It is most
913 // likely changes to the partner bookmarks.
914 JNIEnv
* env
= AttachCurrentThread();
915 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
918 Java_BookmarksBridge_bookmarkModelChanged(env
, obj
.obj());
921 void BookmarksBridge::BookmarkModelLoaded(BookmarkModel
* model
,
922 bool ids_reassigned
) {
923 NotifyIfDoneLoading();
926 void BookmarksBridge::BookmarkModelBeingDeleted(BookmarkModel
* model
) {
930 JNIEnv
* env
= AttachCurrentThread();
931 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
934 Java_BookmarksBridge_bookmarkModelDeleted(env
, obj
.obj());
937 void BookmarksBridge::BookmarkNodeMoved(BookmarkModel
* model
,
938 const BookmarkNode
* old_parent
,
940 const BookmarkNode
* new_parent
,
945 JNIEnv
* env
= AttachCurrentThread();
946 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
949 Java_BookmarksBridge_bookmarkNodeMoved(
952 CreateJavaBookmark(old_parent
).obj(),
954 CreateJavaBookmark(new_parent
).obj(),
958 void BookmarksBridge::BookmarkNodeAdded(BookmarkModel
* model
,
959 const BookmarkNode
* parent
,
964 JNIEnv
* env
= AttachCurrentThread();
965 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
968 Java_BookmarksBridge_bookmarkNodeAdded(
971 CreateJavaBookmark(parent
).obj(),
975 void BookmarksBridge::BookmarkNodeRemoved(BookmarkModel
* model
,
976 const BookmarkNode
* parent
,
978 const BookmarkNode
* node
,
979 const std::set
<GURL
>& removed_urls
) {
983 JNIEnv
* env
= AttachCurrentThread();
984 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
987 Java_BookmarksBridge_bookmarkNodeRemoved(
990 CreateJavaBookmark(parent
).obj(),
992 CreateJavaBookmark(node
).obj());
995 void BookmarksBridge::BookmarkAllUserNodesRemoved(
996 BookmarkModel
* model
,
997 const std::set
<GURL
>& removed_urls
) {
1001 JNIEnv
* env
= AttachCurrentThread();
1002 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
1005 Java_BookmarksBridge_bookmarkAllUserNodesRemoved(env
, obj
.obj());
1008 void BookmarksBridge::BookmarkNodeChanged(BookmarkModel
* model
,
1009 const BookmarkNode
* node
) {
1013 JNIEnv
* env
= AttachCurrentThread();
1014 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
1017 Java_BookmarksBridge_bookmarkNodeChanged(
1020 CreateJavaBookmark(node
).obj());
1023 void BookmarksBridge::BookmarkNodeChildrenReordered(BookmarkModel
* model
,
1024 const BookmarkNode
* node
) {
1028 JNIEnv
* env
= AttachCurrentThread();
1029 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
1032 Java_BookmarksBridge_bookmarkNodeChildrenReordered(
1035 CreateJavaBookmark(node
).obj());
1038 void BookmarksBridge::ExtensiveBookmarkChangesBeginning(BookmarkModel
* model
) {
1042 JNIEnv
* env
= AttachCurrentThread();
1043 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
1046 Java_BookmarksBridge_extensiveBookmarkChangesBeginning(env
, obj
.obj());
1049 void BookmarksBridge::ExtensiveBookmarkChangesEnded(BookmarkModel
* model
) {
1053 JNIEnv
* env
= AttachCurrentThread();
1054 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
1057 Java_BookmarksBridge_extensiveBookmarkChangesEnded(env
, obj
.obj());
1060 void BookmarksBridge::PartnerShimChanged(PartnerBookmarksShim
* shim
) {
1064 BookmarkModelChanged();
1067 void BookmarksBridge::PartnerShimLoaded(PartnerBookmarksShim
* shim
) {
1068 NotifyIfDoneLoading();
1071 void BookmarksBridge::ShimBeingDeleted(PartnerBookmarksShim
* shim
) {
1072 partner_bookmarks_shim_
= NULL
;