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_string.h"
8 #include "base/containers/stack_container.h"
9 #include "base/i18n/string_compare.h"
10 #include "base/prefs/pref_service.h"
11 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
12 #include "chrome/browser/bookmarks/chrome_bookmark_client_factory.h"
13 #include "chrome/browser/bookmarks/enhanced_bookmarks_features.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/profiles/profile_manager.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_model.h"
24 #include "components/bookmarks/browser/bookmark_utils.h"
25 #include "components/bookmarks/browser/scoped_group_bookmark_actions.h"
26 #include "components/bookmarks/common/android/bookmark_type.h"
27 #include "components/signin/core/browser/signin_manager.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "jni/BookmarksBridge_jni.h"
31 using base::android::AttachCurrentThread
;
32 using base::android::ConvertUTF8ToJavaString
;
33 using base::android::ConvertUTF16ToJavaString
;
34 using base::android::ScopedJavaLocalRef
;
35 using base::android::ScopedJavaGlobalRef
;
36 using bookmarks::android::JavaBookmarkIdGetId
;
37 using bookmarks::android::JavaBookmarkIdGetType
;
38 using bookmarks::BookmarkType
;
39 using content::BrowserThread
;
43 class BookmarkNodeCreationTimeCompareFunctor
{
45 bool operator()(const BookmarkNode
* lhs
, const BookmarkNode
* rhs
) {
46 return lhs
->date_added().ToJavaTime() > rhs
->date_added().ToJavaTime();
50 class BookmarkTitleComparer
{
52 explicit BookmarkTitleComparer(const icu::Collator
* collator
)
53 : collator_(collator
) {}
55 bool operator()(const BookmarkNode
* lhs
, const BookmarkNode
* rhs
) {
57 return base::i18n::CompareString16WithCollator(
58 collator_
, lhs
->GetTitle(), rhs
->GetTitle()) == UCOL_LESS
;
60 return lhs
->GetTitle() < rhs
->GetTitle();
65 const icu::Collator
* collator_
;
68 scoped_ptr
<icu::Collator
> GetICUCollator() {
69 UErrorCode error
= U_ZERO_ERROR
;
70 scoped_ptr
<icu::Collator
> collator_
;
71 collator_
.reset(icu::Collator::createInstance(error
));
73 collator_
.reset(NULL
);
75 return collator_
.Pass();
80 BookmarksBridge::BookmarksBridge(JNIEnv
* env
,
83 : weak_java_ref_(env
, obj
),
84 bookmark_model_(NULL
),
86 partner_bookmarks_shim_(NULL
) {
87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
88 profile_
= ProfileAndroid::FromProfileAndroid(j_profile
);
89 bookmark_model_
= BookmarkModelFactory::GetForProfile(profile_
);
90 client_
= ChromeBookmarkClientFactory::GetForProfile(profile_
);
92 // Registers the notifications we are interested.
93 bookmark_model_
->AddObserver(this);
95 // Create the partner Bookmarks shim as early as possible (but don't attach).
96 partner_bookmarks_shim_
= PartnerBookmarksShim::BuildForBrowserContext(
97 chrome::GetBrowserContextRedirectedInIncognito(profile_
));
98 partner_bookmarks_shim_
->AddObserver(this);
100 NotifyIfDoneLoading();
102 // Since a sync or import could have started before this class is
103 // initialized, we need to make sure that our initial state is
105 if (bookmark_model_
->IsDoingExtensiveChanges())
106 ExtensiveBookmarkChangesBeginning(bookmark_model_
);
109 BookmarksBridge::~BookmarksBridge() {
110 bookmark_model_
->RemoveObserver(this);
111 if (partner_bookmarks_shim_
)
112 partner_bookmarks_shim_
->RemoveObserver(this);
115 void BookmarksBridge::Destroy(JNIEnv
*, jobject
) {
120 bool BookmarksBridge::RegisterBookmarksBridge(JNIEnv
* env
) {
121 return RegisterNativesImpl(env
);
124 static jlong
Init(JNIEnv
* env
, jobject obj
, jobject j_profile
) {
125 BookmarksBridge
* delegate
= new BookmarksBridge(env
, obj
, j_profile
);
126 return reinterpret_cast<intptr_t>(delegate
);
129 static jboolean
IsEnhancedBookmarksFeatureEnabled(JNIEnv
* env
,
132 Profile
* profile
= ProfileAndroid::FromProfileAndroid(j_profile
);
133 return IsEnhancedBookmarksEnabled(profile
->GetPrefs());
136 static bool IsEditBookmarksEnabled() {
137 return ProfileManager::GetLastUsedProfile()->GetPrefs()->GetBoolean(
138 bookmarks::prefs::kEditBookmarksEnabled
);
141 static jboolean
IsEditBookmarksEnabled(JNIEnv
* env
, jclass clazz
) {
142 return IsEditBookmarksEnabled();
145 void BookmarksBridge::LoadEmptyPartnerBookmarkShimForTesting(JNIEnv
* env
,
147 if (partner_bookmarks_shim_
->IsLoaded())
149 partner_bookmarks_shim_
->SetPartnerBookmarksRoot(
150 new BookmarkPermanentNode(0));
151 DCHECK(partner_bookmarks_shim_
->IsLoaded());
154 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetBookmarkByID(JNIEnv
* env
,
159 return CreateJavaBookmark(GetNodeByID(id
, type
));
162 bool BookmarksBridge::IsDoingExtensiveChanges(JNIEnv
* env
, jobject obj
) {
163 return bookmark_model_
->IsDoingExtensiveChanges();
166 void BookmarksBridge::GetPermanentNodeIDs(JNIEnv
* env
,
168 jobject j_result_obj
) {
169 // TODO(kkimlabs): Remove this function.
172 base::StackVector
<const BookmarkNode
*, 8> permanent_nodes
;
174 // Save all the permanent nodes.
175 const BookmarkNode
* root_node
= bookmark_model_
->root_node();
176 permanent_nodes
->push_back(root_node
);
177 for (int i
= 0; i
< root_node
->child_count(); ++i
) {
178 permanent_nodes
->push_back(root_node
->GetChild(i
));
180 permanent_nodes
->push_back(
181 partner_bookmarks_shim_
->GetPartnerBookmarksRoot());
183 // Write the permanent nodes to |j_result_obj|.
184 for (base::StackVector
<const BookmarkNode
*, 8>::ContainerType::const_iterator
185 it
= permanent_nodes
->begin();
186 it
!= permanent_nodes
->end();
189 Java_BookmarksBridge_addToBookmarkIdList(
190 env
, j_result_obj
, (*it
)->id(), GetBookmarkType(*it
));
195 void BookmarksBridge::GetTopLevelFolderParentIDs(JNIEnv
* env
,
197 jobject j_result_obj
) {
198 Java_BookmarksBridge_addToBookmarkIdList(
199 env
, j_result_obj
, bookmark_model_
->root_node()->id(),
200 GetBookmarkType(bookmark_model_
->root_node()));
201 Java_BookmarksBridge_addToBookmarkIdList(
202 env
, j_result_obj
, bookmark_model_
->mobile_node()->id(),
203 GetBookmarkType(bookmark_model_
->mobile_node()));
204 Java_BookmarksBridge_addToBookmarkIdList(
205 env
, j_result_obj
, bookmark_model_
->other_node()->id(),
206 GetBookmarkType(bookmark_model_
->other_node()));
209 void BookmarksBridge::GetTopLevelFolderIDs(JNIEnv
* env
,
211 jboolean get_special
,
213 jobject j_result_obj
) {
215 std::vector
<const BookmarkNode
*> top_level_folders
;
218 if (client_
->managed_node() &&
219 client_
->managed_node()->child_count() > 0) {
220 top_level_folders
.push_back(client_
->managed_node());
222 if (partner_bookmarks_shim_
->HasPartnerBookmarks()) {
223 top_level_folders
.push_back(
224 partner_bookmarks_shim_
->GetPartnerBookmarksRoot());
227 std::size_t special_count
= top_level_folders
.size();
230 DCHECK_EQ(bookmark_model_
->root_node()->child_count(), 4);
232 top_level_folders
.push_back(bookmark_model_
->bookmark_bar_node());
234 const BookmarkNode
* mobile_node
= bookmark_model_
->mobile_node();
235 for (int i
= 0; i
< mobile_node
->child_count(); ++i
) {
236 const BookmarkNode
* node
= mobile_node
->GetChild(i
);
237 if (node
->is_folder()) {
238 top_level_folders
.push_back(node
);
242 const BookmarkNode
* other_node
= bookmark_model_
->other_node();
243 for (int i
= 0; i
< other_node
->child_count(); ++i
) {
244 const BookmarkNode
* node
= other_node
->GetChild(i
);
245 if (node
->is_folder()) {
246 top_level_folders
.push_back(node
);
250 scoped_ptr
<icu::Collator
> collator
= GetICUCollator();
251 std::stable_sort(top_level_folders
.begin() + special_count
,
252 top_level_folders
.end(),
253 BookmarkTitleComparer(collator
.get()));
256 for (std::vector
<const BookmarkNode
*>::const_iterator it
=
257 top_level_folders
.begin(); it
!= top_level_folders
.end(); ++it
) {
258 Java_BookmarksBridge_addToBookmarkIdList(env
,
261 GetBookmarkType(*it
));
265 void BookmarksBridge::GetUncategorizedBookmarkIDs(JNIEnv
* env
,
267 jobject j_result_obj
) {
268 const BookmarkNode
* mobile_node
= bookmark_model_
->mobile_node();
269 for (int i
= 0; i
< mobile_node
->child_count(); ++i
) {
270 const BookmarkNode
* node
= mobile_node
->GetChild(i
);
271 if (!node
->is_folder()) {
272 Java_BookmarksBridge_addToBookmarkIdList(env
,
275 GetBookmarkType(node
));
279 const BookmarkNode
* other_node
= bookmark_model_
->other_node();
280 for (int i
= 0; i
< other_node
->child_count(); ++i
) {
281 const BookmarkNode
* node
= other_node
->GetChild(i
);
282 if (!node
->is_folder()) {
283 Java_BookmarksBridge_addToBookmarkIdList(env
,
286 GetBookmarkType(node
));
291 void BookmarksBridge::GetAllFoldersWithDepths(JNIEnv
* env
,
293 jobject j_folders_obj
,
294 jobject j_depths_obj
) {
297 const BookmarkNode
* desktop
= bookmark_model_
->bookmark_bar_node();
298 const BookmarkNode
* mobile
= bookmark_model_
->mobile_node();
299 const BookmarkNode
* other
= bookmark_model_
->other_node();
301 scoped_ptr
<icu::Collator
> collator
= GetICUCollator();
303 // Vector to temporarily contain all child bookmarks at same level for sorting
304 std::vector
<const BookmarkNode
*> bookmarkList
;
305 // Stack for Depth-First Search of bookmark model. It stores nodes and their
307 std::stack
<std::pair
<const BookmarkNode
*, int> > stk
;
309 for (int i
= 0; i
< mobile
->child_count(); ++i
) {
310 const BookmarkNode
* child
= mobile
->GetChild(i
);
311 if (child
->is_folder() && client_
->CanBeEditedByUser(child
))
312 bookmarkList
.push_back(child
);
314 for (int i
= 0; i
< other
->child_count(); ++i
) {
315 const BookmarkNode
* child
= other
->GetChild(i
);
316 if (child
->is_folder() && client_
->CanBeEditedByUser(child
))
317 bookmarkList
.push_back(child
);
319 bookmarkList
.push_back(desktop
);
320 std::stable_sort(bookmarkList
.begin(),
322 BookmarkTitleComparer(collator
.get()));
324 // Push all sorted top folders in stack and give them depth of 0.
325 // Note the order to push folders to stack should be opposite to the order in
327 for (std::vector
<const BookmarkNode
*>::reverse_iterator it
=
328 bookmarkList
.rbegin();
329 it
!= bookmarkList
.rend();
331 stk
.push(std::make_pair(*it
, 0));
334 while (!stk
.empty()) {
335 const BookmarkNode
* node
= stk
.top().first
;
336 int depth
= stk
.top().second
;
338 Java_BookmarksBridge_addToBookmarkIdListWithDepth(env
,
341 GetBookmarkType(node
),
344 bookmarkList
.clear();
345 for (int i
= 0; i
< node
->child_count(); ++i
) {
346 const BookmarkNode
* child
= node
->GetChild(i
);
347 if (child
->is_folder() && client_
->CanBeEditedByUser(child
))
348 bookmarkList
.push_back(node
->GetChild(i
));
350 std::stable_sort(bookmarkList
.begin(),
352 BookmarkTitleComparer(collator
.get()));
353 for (std::vector
<const BookmarkNode
*>::reverse_iterator it
=
354 bookmarkList
.rbegin();
355 it
!= bookmarkList
.rend();
357 stk
.push(std::make_pair(*it
, depth
+ 1));
362 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetMobileFolderId(JNIEnv
* env
,
364 const BookmarkNode
* mobile_node
= bookmark_model_
->mobile_node();
365 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
366 Java_BookmarksBridge_createBookmarkId(
367 env
, mobile_node
->id(), GetBookmarkType(mobile_node
));
368 return folder_id_obj
;
371 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetOtherFolderId(JNIEnv
* env
,
373 const BookmarkNode
* other_node
= bookmark_model_
->other_node();
374 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
375 Java_BookmarksBridge_createBookmarkId(
376 env
, other_node
->id(), GetBookmarkType(other_node
));
377 return folder_id_obj
;
380 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetDesktopFolderId(JNIEnv
* env
,
382 const BookmarkNode
* desktop_node
= bookmark_model_
->bookmark_bar_node();
383 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
384 Java_BookmarksBridge_createBookmarkId(
385 env
, desktop_node
->id(), GetBookmarkType(desktop_node
));
386 return folder_id_obj
;
389 void BookmarksBridge::GetChildIDs(JNIEnv
* env
,
393 jboolean get_folders
,
394 jboolean get_bookmarks
,
395 jobject j_result_obj
) {
398 const BookmarkNode
* parent
= GetNodeByID(id
, type
);
399 if (!parent
->is_folder() || !IsReachable(parent
))
402 // Get the folder contents
403 for (int i
= 0; i
< parent
->child_count(); ++i
) {
404 const BookmarkNode
* child
= parent
->GetChild(i
);
405 if (!IsFolderAvailable(child
) || !IsReachable(child
))
408 if ((child
->is_folder() && get_folders
) ||
409 (!child
->is_folder() && get_bookmarks
)) {
410 Java_BookmarksBridge_addToBookmarkIdList(
411 env
, j_result_obj
, child
->id(), GetBookmarkType(child
));
415 // Partner bookmark root node is under mobile node.
416 if (parent
== bookmark_model_
->mobile_node() && get_folders
&&
417 partner_bookmarks_shim_
->HasPartnerBookmarks() &&
418 IsReachable(partner_bookmarks_shim_
->GetPartnerBookmarksRoot())) {
419 Java_BookmarksBridge_addToBookmarkIdList(
422 partner_bookmarks_shim_
->GetPartnerBookmarksRoot()->id(),
423 BookmarkType::PARTNER
);
427 ScopedJavaLocalRef
<jobject
> BookmarksBridge::GetChildAt(JNIEnv
* env
,
434 const BookmarkNode
* parent
= GetNodeByID(id
, type
);
436 const BookmarkNode
* child
= parent
->GetChild(index
);
437 return Java_BookmarksBridge_createBookmarkId(
438 env
, child
->id(), GetBookmarkType(child
));
441 void BookmarksBridge::GetAllBookmarkIDsOrderedByCreationDate(
444 jobject j_result_obj
) {
446 std::list
<const BookmarkNode
*> folders
;
447 std::vector
<const BookmarkNode
*> result
;
448 folders
.push_back(bookmark_model_
->root_node());
449 folders
.push_back(partner_bookmarks_shim_
->GetPartnerBookmarksRoot());
451 for (std::list
<const BookmarkNode
*>::iterator folder_iter
= folders
.begin();
452 folder_iter
!= folders
.end(); ++folder_iter
) {
453 if (*folder_iter
== NULL
)
456 std::list
<const BookmarkNode
*>::iterator insert_iter
= folder_iter
;
459 for (int i
= 0; i
< (*folder_iter
)->child_count(); ++i
) {
460 const BookmarkNode
* child
= (*folder_iter
)->GetChild(i
);
461 if (!IsFolderAvailable(child
) || !IsReachable(child
))
464 if (child
->is_folder()) {
465 insert_iter
= folders
.insert(insert_iter
, child
);
467 result
.push_back(child
);
473 result
.begin(), result
.end(), BookmarkNodeCreationTimeCompareFunctor());
475 for (std::vector
<const BookmarkNode
*>::const_iterator iter
= result
.begin();
476 iter
!= result
.end();
478 const BookmarkNode
* bookmark
= *iter
;
479 Java_BookmarksBridge_addToBookmarkIdList(
480 env
, j_result_obj
, bookmark
->id(), GetBookmarkType(bookmark
));
484 void BookmarksBridge::SetBookmarkTitle(JNIEnv
* env
,
490 const BookmarkNode
* bookmark
= GetNodeByID(id
, type
);
491 const base::string16 title
=
492 base::android::ConvertJavaStringToUTF16(env
, j_title
);
494 if (partner_bookmarks_shim_
->IsPartnerBookmark(bookmark
)) {
495 partner_bookmarks_shim_
->RenameBookmark(bookmark
, title
);
497 bookmark_model_
->SetTitle(bookmark
, title
);
501 void BookmarksBridge::SetBookmarkUrl(JNIEnv
* env
,
507 bookmark_model_
->SetURL(
508 GetNodeByID(id
, type
),
509 GURL(base::android::ConvertJavaStringToUTF16(env
, url
)));
512 bool BookmarksBridge::DoesBookmarkExist(JNIEnv
* env
,
517 return GetNodeByID(id
, type
);
520 void BookmarksBridge::GetBookmarksForFolder(JNIEnv
* env
,
522 jobject j_folder_id_obj
,
523 jobject j_callback_obj
,
524 jobject j_result_obj
) {
526 long folder_id
= JavaBookmarkIdGetId(env
, j_folder_id_obj
);
527 int type
= JavaBookmarkIdGetType(env
, j_folder_id_obj
);
528 const BookmarkNode
* folder
= GetFolderWithFallback(folder_id
, type
);
530 if (!folder
->is_folder() || !IsReachable(folder
))
533 // Recreate the java bookmarkId object due to fallback.
534 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
535 Java_BookmarksBridge_createBookmarkId(
536 env
, folder
->id(), GetBookmarkType(folder
));
537 j_folder_id_obj
= folder_id_obj
.obj();
539 // Get the folder contents.
540 for (int i
= 0; i
< folder
->child_count(); ++i
) {
541 const BookmarkNode
* node
= folder
->GetChild(i
);
542 if (!IsFolderAvailable(node
))
544 ExtractBookmarkNodeInformation(node
, j_result_obj
);
547 if (folder
== bookmark_model_
->mobile_node() &&
548 partner_bookmarks_shim_
->HasPartnerBookmarks()) {
549 ExtractBookmarkNodeInformation(
550 partner_bookmarks_shim_
->GetPartnerBookmarksRoot(),
554 if (j_callback_obj
) {
555 Java_BookmarksCallback_onBookmarksAvailable(
556 env
, j_callback_obj
, j_folder_id_obj
, j_result_obj
);
560 void BookmarksBridge::GetCurrentFolderHierarchy(JNIEnv
* env
,
562 jobject j_folder_id_obj
,
563 jobject j_callback_obj
,
564 jobject j_result_obj
) {
566 long folder_id
= JavaBookmarkIdGetId(env
, j_folder_id_obj
);
567 int type
= JavaBookmarkIdGetType(env
, j_folder_id_obj
);
568 const BookmarkNode
* folder
= GetFolderWithFallback(folder_id
, type
);
570 if (!folder
->is_folder() || !IsReachable(folder
))
573 // Recreate the java bookmarkId object due to fallback.
574 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
575 Java_BookmarksBridge_createBookmarkId(
576 env
, folder
->id(), GetBookmarkType(folder
));
577 j_folder_id_obj
= folder_id_obj
.obj();
579 // Get the folder hierarchy.
580 const BookmarkNode
* node
= folder
;
582 ExtractBookmarkNodeInformation(node
, j_result_obj
);
583 node
= GetParentNode(node
);
586 Java_BookmarksCallback_onBookmarksFolderHierarchyAvailable(
587 env
, j_callback_obj
, j_folder_id_obj
, j_result_obj
);
590 ScopedJavaLocalRef
<jobject
> BookmarksBridge::AddFolder(JNIEnv
* env
,
592 jobject j_parent_id_obj
,
596 long bookmark_id
= JavaBookmarkIdGetId(env
, j_parent_id_obj
);
597 int type
= JavaBookmarkIdGetType(env
, j_parent_id_obj
);
598 const BookmarkNode
* parent
= GetNodeByID(bookmark_id
, type
);
600 const BookmarkNode
* new_node
= bookmark_model_
->AddFolder(
601 parent
, index
, base::android::ConvertJavaStringToUTF16(env
, j_title
));
604 return ScopedJavaLocalRef
<jobject
>();
606 ScopedJavaLocalRef
<jobject
> new_java_obj
=
607 Java_BookmarksBridge_createBookmarkId(
608 env
, new_node
->id(), GetBookmarkType(new_node
));
612 void BookmarksBridge::DeleteBookmark(JNIEnv
* env
,
614 jobject j_bookmark_id_obj
) {
615 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
618 long bookmark_id
= JavaBookmarkIdGetId(env
, j_bookmark_id_obj
);
619 int type
= JavaBookmarkIdGetType(env
, j_bookmark_id_obj
);
620 const BookmarkNode
* node
= GetNodeByID(bookmark_id
, type
);
621 if (!IsEditable(node
)) {
626 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
)) {
627 partner_bookmarks_shim_
->RemoveBookmark(node
);
629 const BookmarkNode
* parent_node
= GetParentNode(node
);
630 bookmark_model_
->Remove(parent_node
, parent_node
->GetIndexOf(node
));
634 void BookmarksBridge::MoveBookmark(JNIEnv
* env
,
636 jobject j_bookmark_id_obj
,
637 jobject j_parent_id_obj
,
639 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
642 long bookmark_id
= JavaBookmarkIdGetId(env
, j_bookmark_id_obj
);
643 int type
= JavaBookmarkIdGetType(env
, j_bookmark_id_obj
);
644 const BookmarkNode
* node
= GetNodeByID(bookmark_id
, type
);
645 if (!IsEditable(node
)) {
649 bookmark_id
= JavaBookmarkIdGetId(env
, j_parent_id_obj
);
650 type
= JavaBookmarkIdGetType(env
, j_parent_id_obj
);
651 const BookmarkNode
* new_parent_node
= GetNodeByID(bookmark_id
, type
);
652 bookmark_model_
->Move(node
, new_parent_node
, index
);
655 ScopedJavaLocalRef
<jobject
> BookmarksBridge::AddBookmark(
658 jobject j_parent_id_obj
,
663 long bookmark_id
= JavaBookmarkIdGetId(env
, j_parent_id_obj
);
664 int type
= JavaBookmarkIdGetType(env
, j_parent_id_obj
);
665 const BookmarkNode
* parent
= GetNodeByID(bookmark_id
, type
);
667 const BookmarkNode
* new_node
= bookmark_model_
->AddURL(
670 base::android::ConvertJavaStringToUTF16(env
, j_title
),
671 GURL(base::android::ConvertJavaStringToUTF16(env
, j_url
)));
674 return ScopedJavaLocalRef
<jobject
>();
676 ScopedJavaLocalRef
<jobject
> new_java_obj
=
677 Java_BookmarksBridge_createBookmarkId(
678 env
, new_node
->id(), GetBookmarkType(new_node
));
682 void BookmarksBridge::Undo(JNIEnv
* env
, jobject obj
) {
683 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
685 BookmarkUndoService
* undo_service
=
686 BookmarkUndoServiceFactory::GetForProfile(profile_
);
687 UndoManager
* undo_manager
= undo_service
->undo_manager();
688 undo_manager
->Undo();
691 void BookmarksBridge::StartGroupingUndos(JNIEnv
* env
, jobject obj
) {
692 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
694 DCHECK(!grouped_bookmark_actions_
.get()); // shouldn't have started already
695 grouped_bookmark_actions_
.reset(
696 new bookmarks::ScopedGroupBookmarkActions(bookmark_model_
));
699 void BookmarksBridge::EndGroupingUndos(JNIEnv
* env
, jobject obj
) {
700 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
702 DCHECK(grouped_bookmark_actions_
.get()); // should only call after start
703 grouped_bookmark_actions_
.reset();
706 ScopedJavaLocalRef
<jobject
> BookmarksBridge::CreateJavaBookmark(
707 const BookmarkNode
* node
) {
708 JNIEnv
* env
= AttachCurrentThread();
710 const BookmarkNode
* parent
= GetParentNode(node
);
711 int64 parent_id
= parent
? parent
->id() : -1;
715 url
= node
->url().spec();
717 return Java_BookmarksBridge_createBookmarkItem(
720 GetBookmarkType(node
),
721 ConvertUTF16ToJavaString(env
, GetTitle(node
)).obj(),
722 ConvertUTF8ToJavaString(env
, url
).obj(),
725 GetBookmarkType(parent
),
730 void BookmarksBridge::ExtractBookmarkNodeInformation(const BookmarkNode
* node
,
731 jobject j_result_obj
) {
732 JNIEnv
* env
= AttachCurrentThread();
733 if (!IsReachable(node
))
735 Java_BookmarksBridge_addToList(
736 env
, j_result_obj
, CreateJavaBookmark(node
).obj());
739 const BookmarkNode
* BookmarksBridge::GetNodeByID(long node_id
, int type
) {
740 const BookmarkNode
* node
;
741 if (type
== BookmarkType::PARTNER
) {
742 node
= partner_bookmarks_shim_
->GetNodeByID(
743 static_cast<int64
>(node_id
));
745 node
= bookmarks::GetBookmarkNodeByID(bookmark_model_
,
746 static_cast<int64
>(node_id
));
751 const BookmarkNode
* BookmarksBridge::GetFolderWithFallback(long folder_id
,
753 const BookmarkNode
* folder
= GetNodeByID(folder_id
, type
);
754 if (!folder
|| folder
->type() == BookmarkNode::URL
||
755 !IsFolderAvailable(folder
)) {
756 if (!client_
->managed_node()->empty())
757 folder
= client_
->managed_node();
759 folder
= bookmark_model_
->mobile_node();
764 bool BookmarksBridge::IsEditable(const BookmarkNode
* node
) const {
765 if (!node
|| (node
->type() != BookmarkNode::FOLDER
&&
766 node
->type() != BookmarkNode::URL
)) {
769 if (!IsEditBookmarksEnabled())
771 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
772 return partner_bookmarks_shim_
->IsEditable(node
);
773 return client_
->CanBeEditedByUser(node
);
776 bool BookmarksBridge::IsManaged(const BookmarkNode
* node
) const {
777 return client_
->IsDescendantOfManagedNode(node
);
780 const BookmarkNode
* BookmarksBridge::GetParentNode(const BookmarkNode
* node
) {
782 if (node
== partner_bookmarks_shim_
->GetPartnerBookmarksRoot()) {
783 return bookmark_model_
->mobile_node();
785 return node
->parent();
789 int BookmarksBridge::GetBookmarkType(const BookmarkNode
* node
) {
790 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
791 return BookmarkType::PARTNER
;
793 return BookmarkType::NORMAL
;
796 base::string16
BookmarksBridge::GetTitle(const BookmarkNode
* node
) const {
797 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
798 return partner_bookmarks_shim_
->GetTitle(node
);
799 return node
->GetTitle();
802 bool BookmarksBridge::IsReachable(const BookmarkNode
* node
) const {
803 if (!partner_bookmarks_shim_
->IsPartnerBookmark(node
))
805 return partner_bookmarks_shim_
->IsReachable(node
);
808 bool BookmarksBridge::IsLoaded() const {
809 return (bookmark_model_
->loaded() && partner_bookmarks_shim_
->IsLoaded());
812 bool BookmarksBridge::IsFolderAvailable(
813 const BookmarkNode
* folder
) const {
814 // The managed bookmarks folder is not shown if there are no bookmarks
815 // configured via policy.
816 if (folder
== client_
->managed_node() && folder
->empty())
819 SigninManager
* signin
= SigninManagerFactory::GetForProfile(
820 profile_
->GetOriginalProfile());
821 return (folder
->type() != BookmarkNode::BOOKMARK_BAR
&&
822 folder
->type() != BookmarkNode::OTHER_NODE
) ||
823 (signin
&& signin
->IsAuthenticated());
826 void BookmarksBridge::NotifyIfDoneLoading() {
829 JNIEnv
* env
= AttachCurrentThread();
830 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
833 Java_BookmarksBridge_bookmarkModelLoaded(env
, obj
.obj());
836 // ------------- Observer-related methods ------------- //
838 void BookmarksBridge::BookmarkModelChanged() {
842 // Called when there are changes to the bookmark model. It is most
843 // likely changes to the partner bookmarks.
844 JNIEnv
* env
= AttachCurrentThread();
845 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
848 Java_BookmarksBridge_bookmarkModelChanged(env
, obj
.obj());
851 void BookmarksBridge::BookmarkModelLoaded(BookmarkModel
* model
,
852 bool ids_reassigned
) {
853 NotifyIfDoneLoading();
856 void BookmarksBridge::BookmarkModelBeingDeleted(BookmarkModel
* model
) {
860 JNIEnv
* env
= AttachCurrentThread();
861 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
864 Java_BookmarksBridge_bookmarkModelDeleted(env
, obj
.obj());
867 void BookmarksBridge::BookmarkNodeMoved(BookmarkModel
* model
,
868 const BookmarkNode
* old_parent
,
870 const BookmarkNode
* new_parent
,
875 JNIEnv
* env
= AttachCurrentThread();
876 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
879 Java_BookmarksBridge_bookmarkNodeMoved(
882 CreateJavaBookmark(old_parent
).obj(),
884 CreateJavaBookmark(new_parent
).obj(),
888 void BookmarksBridge::BookmarkNodeAdded(BookmarkModel
* model
,
889 const BookmarkNode
* parent
,
894 JNIEnv
* env
= AttachCurrentThread();
895 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
898 Java_BookmarksBridge_bookmarkNodeAdded(
901 CreateJavaBookmark(parent
).obj(),
905 void BookmarksBridge::BookmarkNodeRemoved(BookmarkModel
* model
,
906 const BookmarkNode
* parent
,
908 const BookmarkNode
* node
,
909 const std::set
<GURL
>& removed_urls
) {
913 JNIEnv
* env
= AttachCurrentThread();
914 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
917 Java_BookmarksBridge_bookmarkNodeRemoved(
920 CreateJavaBookmark(parent
).obj(),
922 CreateJavaBookmark(node
).obj());
925 void BookmarksBridge::BookmarkNodeChanged(BookmarkModel
* model
,
926 const BookmarkNode
* node
) {
930 JNIEnv
* env
= AttachCurrentThread();
931 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
934 Java_BookmarksBridge_bookmarkNodeChanged(
937 CreateJavaBookmark(node
).obj());
940 void BookmarksBridge::BookmarkNodeChildrenReordered(BookmarkModel
* model
,
941 const BookmarkNode
* node
) {
945 JNIEnv
* env
= AttachCurrentThread();
946 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
949 Java_BookmarksBridge_bookmarkNodeChildrenReordered(
952 CreateJavaBookmark(node
).obj());
955 void BookmarksBridge::ExtensiveBookmarkChangesBeginning(BookmarkModel
* model
) {
959 JNIEnv
* env
= AttachCurrentThread();
960 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
963 Java_BookmarksBridge_extensiveBookmarkChangesBeginning(env
, obj
.obj());
966 void BookmarksBridge::ExtensiveBookmarkChangesEnded(BookmarkModel
* model
) {
970 JNIEnv
* env
= AttachCurrentThread();
971 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
974 Java_BookmarksBridge_extensiveBookmarkChangesEnded(env
, obj
.obj());
977 void BookmarksBridge::PartnerShimChanged(PartnerBookmarksShim
* shim
) {
981 BookmarkModelChanged();
984 void BookmarksBridge::PartnerShimLoaded(PartnerBookmarksShim
* shim
) {
985 NotifyIfDoneLoading();
988 void BookmarksBridge::ShimBeingDeleted(PartnerBookmarksShim
* shim
) {
989 partner_bookmarks_shim_
= NULL
;