Exclude partner/managed bookmarks from all items
[chromium-blink-merge.git] / chrome / browser / android / bookmarks / bookmarks_bridge.cc
blob3b61a340c6ed516bb3a2e768a988192f4371af95
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_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 "jni/BookmarksBridge_jni.h"
33 using base::android::AttachCurrentThread;
34 using base::android::ConvertUTF8ToJavaString;
35 using base::android::ConvertUTF16ToJavaString;
36 using base::android::ScopedJavaLocalRef;
37 using base::android::ScopedJavaGlobalRef;
38 using bookmarks::android::JavaBookmarkIdCreateBookmarkId;
39 using bookmarks::android::JavaBookmarkIdGetId;
40 using bookmarks::android::JavaBookmarkIdGetType;
41 using bookmarks::BookmarkType;
42 using content::BrowserThread;
44 namespace {
46 class BookmarkNodeCreationTimeCompareFunctor {
47 public:
48 bool operator()(const BookmarkNode* lhs, const BookmarkNode* rhs) {
49 return lhs->date_added().ToJavaTime() > rhs->date_added().ToJavaTime();
53 class BookmarkTitleComparer {
54 public:
55 explicit BookmarkTitleComparer(const icu::Collator* collator)
56 : collator_(collator) {}
58 bool operator()(const BookmarkNode* lhs, const BookmarkNode* rhs) {
59 if (collator_) {
60 return base::i18n::CompareString16WithCollator(
61 collator_, lhs->GetTitle(), rhs->GetTitle()) == UCOL_LESS;
62 } else {
63 return lhs->GetTitle() < rhs->GetTitle();
67 private:
68 const icu::Collator* collator_;
71 scoped_ptr<icu::Collator> GetICUCollator() {
72 UErrorCode error = U_ZERO_ERROR;
73 scoped_ptr<icu::Collator> collator_;
74 collator_.reset(icu::Collator::createInstance(error));
75 if (U_FAILURE(error))
76 collator_.reset(NULL);
78 return collator_.Pass();
81 } // namespace
83 BookmarksBridge::BookmarksBridge(JNIEnv* env,
84 jobject obj,
85 jobject j_profile)
86 : weak_java_ref_(env, obj),
87 bookmark_model_(NULL),
88 client_(NULL),
89 partner_bookmarks_shim_(NULL) {
90 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
91 profile_ = ProfileAndroid::FromProfileAndroid(j_profile);
92 bookmark_model_ = BookmarkModelFactory::GetForProfile(profile_);
93 client_ = ChromeBookmarkClientFactory::GetForProfile(profile_);
95 // Registers the notifications we are interested.
96 bookmark_model_->AddObserver(this);
98 // Create the partner Bookmarks shim as early as possible (but don't attach).
99 partner_bookmarks_shim_ = PartnerBookmarksShim::BuildForBrowserContext(
100 chrome::GetBrowserContextRedirectedInIncognito(profile_));
101 partner_bookmarks_shim_->AddObserver(this);
103 NotifyIfDoneLoading();
105 // Since a sync or import could have started before this class is
106 // initialized, we need to make sure that our initial state is
107 // up to date.
108 if (bookmark_model_->IsDoingExtensiveChanges())
109 ExtensiveBookmarkChangesBeginning(bookmark_model_);
112 BookmarksBridge::~BookmarksBridge() {
113 bookmark_model_->RemoveObserver(this);
114 if (partner_bookmarks_shim_)
115 partner_bookmarks_shim_->RemoveObserver(this);
118 void BookmarksBridge::Destroy(JNIEnv*, jobject) {
119 delete this;
122 // static
123 bool BookmarksBridge::RegisterBookmarksBridge(JNIEnv* env) {
124 return RegisterNativesImpl(env);
127 static jlong Init(JNIEnv* env, jobject obj, jobject j_profile) {
128 BookmarksBridge* delegate = new BookmarksBridge(env, obj, j_profile);
129 return reinterpret_cast<intptr_t>(delegate);
132 static jboolean IsEnhancedBookmarksFeatureEnabled(JNIEnv* env,
133 jclass clazz,
134 jobject j_profile) {
135 Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
136 return IsEnhancedBookmarksEnabled(profile->GetPrefs());
139 static bool IsEditBookmarksEnabled() {
140 return ProfileManager::GetLastUsedProfile()->GetPrefs()->GetBoolean(
141 bookmarks::prefs::kEditBookmarksEnabled);
144 static jboolean IsEditBookmarksEnabled(JNIEnv* env, jclass clazz) {
145 return IsEditBookmarksEnabled();
148 void BookmarksBridge::LoadEmptyPartnerBookmarkShimForTesting(JNIEnv* env,
149 jobject obj) {
150 if (partner_bookmarks_shim_->IsLoaded())
151 return;
152 partner_bookmarks_shim_->SetPartnerBookmarksRoot(
153 new BookmarkPermanentNode(0));
154 DCHECK(partner_bookmarks_shim_->IsLoaded());
157 ScopedJavaLocalRef<jobject> BookmarksBridge::GetBookmarkByID(JNIEnv* env,
158 jobject obj,
159 jlong id,
160 jint type) {
161 DCHECK(IsLoaded());
162 return CreateJavaBookmark(GetNodeByID(id, type));
165 bool BookmarksBridge::IsDoingExtensiveChanges(JNIEnv* env, jobject obj) {
166 return bookmark_model_->IsDoingExtensiveChanges();
169 void BookmarksBridge::GetPermanentNodeIDs(JNIEnv* env,
170 jobject obj,
171 jobject j_result_obj) {
172 // TODO(kkimlabs): Remove this function.
173 DCHECK(IsLoaded());
175 base::StackVector<const BookmarkNode*, 8> permanent_nodes;
177 // Save all the permanent nodes.
178 const BookmarkNode* root_node = bookmark_model_->root_node();
179 permanent_nodes->push_back(root_node);
180 for (int i = 0; i < root_node->child_count(); ++i) {
181 permanent_nodes->push_back(root_node->GetChild(i));
183 permanent_nodes->push_back(
184 partner_bookmarks_shim_->GetPartnerBookmarksRoot());
186 // Write the permanent nodes to |j_result_obj|.
187 for (base::StackVector<const BookmarkNode*, 8>::ContainerType::const_iterator
188 it = permanent_nodes->begin();
189 it != permanent_nodes->end();
190 ++it) {
191 if (*it != NULL) {
192 Java_BookmarksBridge_addToBookmarkIdList(
193 env, j_result_obj, (*it)->id(), GetBookmarkType(*it));
198 void BookmarksBridge::GetTopLevelFolderParentIDs(JNIEnv* env,
199 jobject obj,
200 jobject j_result_obj) {
201 Java_BookmarksBridge_addToBookmarkIdList(
202 env, j_result_obj, bookmark_model_->root_node()->id(),
203 GetBookmarkType(bookmark_model_->root_node()));
204 Java_BookmarksBridge_addToBookmarkIdList(
205 env, j_result_obj, bookmark_model_->mobile_node()->id(),
206 GetBookmarkType(bookmark_model_->mobile_node()));
207 Java_BookmarksBridge_addToBookmarkIdList(
208 env, j_result_obj, bookmark_model_->other_node()->id(),
209 GetBookmarkType(bookmark_model_->other_node()));
212 void BookmarksBridge::GetTopLevelFolderIDs(JNIEnv* env,
213 jobject obj,
214 jboolean get_special,
215 jboolean get_normal,
216 jobject j_result_obj) {
217 DCHECK(IsLoaded());
218 std::vector<const BookmarkNode*> top_level_folders;
220 if (get_special) {
221 if (client_->managed_node() &&
222 client_->managed_node()->child_count() > 0) {
223 top_level_folders.push_back(client_->managed_node());
225 if (partner_bookmarks_shim_->HasPartnerBookmarks()) {
226 top_level_folders.push_back(
227 partner_bookmarks_shim_->GetPartnerBookmarksRoot());
230 std::size_t special_count = top_level_folders.size();
232 if (get_normal) {
233 DCHECK_EQ(bookmark_model_->root_node()->child_count(), 4);
235 top_level_folders.push_back(bookmark_model_->bookmark_bar_node());
237 const BookmarkNode* mobile_node = bookmark_model_->mobile_node();
238 for (int i = 0; i < mobile_node->child_count(); ++i) {
239 const BookmarkNode* node = mobile_node->GetChild(i);
240 if (node->is_folder()) {
241 top_level_folders.push_back(node);
245 const BookmarkNode* other_node = bookmark_model_->other_node();
246 for (int i = 0; i < other_node->child_count(); ++i) {
247 const BookmarkNode* node = other_node->GetChild(i);
248 if (node->is_folder()) {
249 top_level_folders.push_back(node);
253 scoped_ptr<icu::Collator> collator = GetICUCollator();
254 std::stable_sort(top_level_folders.begin() + special_count,
255 top_level_folders.end(),
256 BookmarkTitleComparer(collator.get()));
259 for (std::vector<const BookmarkNode*>::const_iterator it =
260 top_level_folders.begin(); it != top_level_folders.end(); ++it) {
261 Java_BookmarksBridge_addToBookmarkIdList(env,
262 j_result_obj,
263 (*it)->id(),
264 GetBookmarkType(*it));
268 void BookmarksBridge::GetUncategorizedBookmarkIDs(JNIEnv* env,
269 jobject obj,
270 jobject j_result_obj) {
271 const BookmarkNode* mobile_node = bookmark_model_->mobile_node();
272 for (int i = 0; i < mobile_node->child_count(); ++i) {
273 const BookmarkNode* node = mobile_node->GetChild(i);
274 if (!node->is_folder()) {
275 Java_BookmarksBridge_addToBookmarkIdList(env,
276 j_result_obj,
277 node->id(),
278 GetBookmarkType(node));
282 const BookmarkNode* other_node = bookmark_model_->other_node();
283 for (int i = 0; i < other_node->child_count(); ++i) {
284 const BookmarkNode* node = other_node->GetChild(i);
285 if (!node->is_folder()) {
286 Java_BookmarksBridge_addToBookmarkIdList(env,
287 j_result_obj,
288 node->id(),
289 GetBookmarkType(node));
294 void BookmarksBridge::GetAllFoldersWithDepths(JNIEnv* env,
295 jobject obj,
296 jobject j_folders_obj,
297 jobject j_depths_obj) {
298 DCHECK(IsLoaded());
300 const BookmarkNode* desktop = bookmark_model_->bookmark_bar_node();
301 const BookmarkNode* mobile = bookmark_model_->mobile_node();
302 const BookmarkNode* other = bookmark_model_->other_node();
304 scoped_ptr<icu::Collator> collator = GetICUCollator();
306 // Vector to temporarily contain all child bookmarks at same level for sorting
307 std::vector<const BookmarkNode*> bookmarkList;
308 // Stack for Depth-First Search of bookmark model. It stores nodes and their
309 // heights.
310 std::stack<std::pair<const BookmarkNode*, int> > stk;
312 for (int i = 0; i < mobile->child_count(); ++i) {
313 const BookmarkNode* child = mobile->GetChild(i);
314 if (child->is_folder() && client_->CanBeEditedByUser(child))
315 bookmarkList.push_back(child);
317 for (int i = 0; i < other->child_count(); ++i) {
318 const BookmarkNode* child = other->GetChild(i);
319 if (child->is_folder() && client_->CanBeEditedByUser(child))
320 bookmarkList.push_back(child);
322 bookmarkList.push_back(desktop);
323 std::stable_sort(bookmarkList.begin(),
324 bookmarkList.end(),
325 BookmarkTitleComparer(collator.get()));
327 // Push all sorted top folders in stack and give them depth of 0.
328 // Note the order to push folders to stack should be opposite to the order in
329 // output.
330 for (std::vector<const BookmarkNode*>::reverse_iterator it =
331 bookmarkList.rbegin();
332 it != bookmarkList.rend();
333 ++it) {
334 stk.push(std::make_pair(*it, 0));
337 while (!stk.empty()) {
338 const BookmarkNode* node = stk.top().first;
339 int depth = stk.top().second;
340 stk.pop();
341 Java_BookmarksBridge_addToBookmarkIdListWithDepth(env,
342 j_folders_obj,
343 node->id(),
344 GetBookmarkType(node),
345 j_depths_obj,
346 depth);
347 bookmarkList.clear();
348 for (int i = 0; i < node->child_count(); ++i) {
349 const BookmarkNode* child = node->GetChild(i);
350 if (child->is_folder() && client_->CanBeEditedByUser(child))
351 bookmarkList.push_back(node->GetChild(i));
353 std::stable_sort(bookmarkList.begin(),
354 bookmarkList.end(),
355 BookmarkTitleComparer(collator.get()));
356 for (std::vector<const BookmarkNode*>::reverse_iterator it =
357 bookmarkList.rbegin();
358 it != bookmarkList.rend();
359 ++it) {
360 stk.push(std::make_pair(*it, depth + 1));
365 ScopedJavaLocalRef<jobject> BookmarksBridge::GetMobileFolderId(JNIEnv* env,
366 jobject obj) {
367 const BookmarkNode* mobile_node = bookmark_model_->mobile_node();
368 ScopedJavaLocalRef<jobject> folder_id_obj =
369 JavaBookmarkIdCreateBookmarkId(
370 env, mobile_node->id(), GetBookmarkType(mobile_node));
371 return folder_id_obj;
374 ScopedJavaLocalRef<jobject> BookmarksBridge::GetOtherFolderId(JNIEnv* env,
375 jobject obj) {
376 const BookmarkNode* other_node = bookmark_model_->other_node();
377 ScopedJavaLocalRef<jobject> folder_id_obj =
378 JavaBookmarkIdCreateBookmarkId(
379 env, other_node->id(), GetBookmarkType(other_node));
380 return folder_id_obj;
383 ScopedJavaLocalRef<jobject> BookmarksBridge::GetDesktopFolderId(JNIEnv* env,
384 jobject obj) {
385 const BookmarkNode* desktop_node = bookmark_model_->bookmark_bar_node();
386 ScopedJavaLocalRef<jobject> folder_id_obj =
387 JavaBookmarkIdCreateBookmarkId(
388 env, desktop_node->id(), GetBookmarkType(desktop_node));
389 return folder_id_obj;
392 void BookmarksBridge::GetChildIDs(JNIEnv* env,
393 jobject obj,
394 jlong id,
395 jint type,
396 jboolean get_folders,
397 jboolean get_bookmarks,
398 jobject j_result_obj) {
399 DCHECK(IsLoaded());
401 const BookmarkNode* parent = GetNodeByID(id, type);
402 if (!parent->is_folder() || !IsReachable(parent))
403 return;
405 // Get the folder contents
406 for (int i = 0; i < parent->child_count(); ++i) {
407 const BookmarkNode* child = parent->GetChild(i);
408 if (!IsFolderAvailable(child) || !IsReachable(child))
409 continue;
411 if ((child->is_folder() && get_folders) ||
412 (!child->is_folder() && get_bookmarks)) {
413 Java_BookmarksBridge_addToBookmarkIdList(
414 env, j_result_obj, child->id(), GetBookmarkType(child));
418 // Partner bookmark root node is under mobile node.
419 if (parent == bookmark_model_->mobile_node() && get_folders &&
420 partner_bookmarks_shim_->HasPartnerBookmarks() &&
421 IsReachable(partner_bookmarks_shim_->GetPartnerBookmarksRoot())) {
422 Java_BookmarksBridge_addToBookmarkIdList(
423 env,
424 j_result_obj,
425 partner_bookmarks_shim_->GetPartnerBookmarksRoot()->id(),
426 BookmarkType::BOOKMARK_TYPE_PARTNER);
430 ScopedJavaLocalRef<jobject> BookmarksBridge::GetChildAt(JNIEnv* env,
431 jobject obj,
432 jlong id,
433 jint type,
434 jint index) {
435 DCHECK(IsLoaded());
437 const BookmarkNode* parent = GetNodeByID(id, type);
438 DCHECK(parent);
439 const BookmarkNode* child = parent->GetChild(index);
440 return JavaBookmarkIdCreateBookmarkId(
441 env, child->id(), GetBookmarkType(child));
444 void BookmarksBridge::GetAllBookmarkIDsOrderedByCreationDate(
445 JNIEnv* env,
446 jobject obj,
447 jobject j_result_obj) {
448 DCHECK(IsLoaded());
449 std::list<const BookmarkNode*> folders;
450 std::vector<const BookmarkNode*> result;
451 folders.push_back(bookmark_model_->root_node());
453 for (std::list<const BookmarkNode*>::iterator folder_iter = folders.begin();
454 folder_iter != folders.end(); ++folder_iter) {
455 if (*folder_iter == NULL)
456 continue;
458 std::list<const BookmarkNode*>::iterator insert_iter = folder_iter;
459 ++insert_iter;
461 for (int i = 0; i < (*folder_iter)->child_count(); ++i) {
462 const BookmarkNode* child = (*folder_iter)->GetChild(i);
463 if (!IsFolderAvailable(child) || !IsReachable(child) ||
464 client_->IsDescendantOfManagedNode(child))
465 continue;
467 if (child->is_folder()) {
468 insert_iter = folders.insert(insert_iter, child);
469 } else {
470 result.push_back(child);
475 std::sort(
476 result.begin(), result.end(), BookmarkNodeCreationTimeCompareFunctor());
478 for (std::vector<const BookmarkNode*>::const_iterator iter = result.begin();
479 iter != result.end();
480 ++iter) {
481 const BookmarkNode* bookmark = *iter;
482 Java_BookmarksBridge_addToBookmarkIdList(
483 env, j_result_obj, bookmark->id(), GetBookmarkType(bookmark));
487 void BookmarksBridge::SetBookmarkTitle(JNIEnv* env,
488 jobject obj,
489 jlong id,
490 jint type,
491 jstring j_title) {
492 DCHECK(IsLoaded());
493 const BookmarkNode* bookmark = GetNodeByID(id, type);
494 const base::string16 title =
495 base::android::ConvertJavaStringToUTF16(env, j_title);
497 if (partner_bookmarks_shim_->IsPartnerBookmark(bookmark)) {
498 partner_bookmarks_shim_->RenameBookmark(bookmark, title);
499 } else {
500 bookmark_model_->SetTitle(bookmark, title);
504 void BookmarksBridge::SetBookmarkUrl(JNIEnv* env,
505 jobject obj,
506 jlong id,
507 jint type,
508 jstring url) {
509 DCHECK(IsLoaded());
510 bookmark_model_->SetURL(
511 GetNodeByID(id, type),
512 GURL(base::android::ConvertJavaStringToUTF16(env, url)));
515 bool BookmarksBridge::DoesBookmarkExist(JNIEnv* env,
516 jobject obj,
517 jlong id,
518 jint type) {
519 DCHECK(IsLoaded());
520 return GetNodeByID(id, type);
523 void BookmarksBridge::GetBookmarksForFolder(JNIEnv* env,
524 jobject obj,
525 jobject j_folder_id_obj,
526 jobject j_callback_obj,
527 jobject j_result_obj) {
528 DCHECK(IsLoaded());
529 long folder_id = JavaBookmarkIdGetId(env, j_folder_id_obj);
530 int type = JavaBookmarkIdGetType(env, j_folder_id_obj);
531 const BookmarkNode* folder = GetFolderWithFallback(folder_id, type);
533 if (!folder->is_folder() || !IsReachable(folder))
534 return;
536 // Recreate the java bookmarkId object due to fallback.
537 ScopedJavaLocalRef<jobject> folder_id_obj =
538 JavaBookmarkIdCreateBookmarkId(
539 env, folder->id(), GetBookmarkType(folder));
540 j_folder_id_obj = folder_id_obj.obj();
542 // Get the folder contents.
543 for (int i = 0; i < folder->child_count(); ++i) {
544 const BookmarkNode* node = folder->GetChild(i);
545 if (!IsFolderAvailable(node))
546 continue;
547 ExtractBookmarkNodeInformation(node, j_result_obj);
550 if (folder == bookmark_model_->mobile_node() &&
551 partner_bookmarks_shim_->HasPartnerBookmarks()) {
552 ExtractBookmarkNodeInformation(
553 partner_bookmarks_shim_->GetPartnerBookmarksRoot(),
554 j_result_obj);
557 if (j_callback_obj) {
558 Java_BookmarksCallback_onBookmarksAvailable(
559 env, j_callback_obj, j_folder_id_obj, j_result_obj);
563 void BookmarksBridge::GetCurrentFolderHierarchy(JNIEnv* env,
564 jobject obj,
565 jobject j_folder_id_obj,
566 jobject j_callback_obj,
567 jobject j_result_obj) {
568 DCHECK(IsLoaded());
569 long folder_id = JavaBookmarkIdGetId(env, j_folder_id_obj);
570 int type = JavaBookmarkIdGetType(env, j_folder_id_obj);
571 const BookmarkNode* folder = GetFolderWithFallback(folder_id, type);
573 if (!folder->is_folder() || !IsReachable(folder))
574 return;
576 // Recreate the java bookmarkId object due to fallback.
577 ScopedJavaLocalRef<jobject> folder_id_obj =
578 JavaBookmarkIdCreateBookmarkId(
579 env, folder->id(), GetBookmarkType(folder));
580 j_folder_id_obj = folder_id_obj.obj();
582 // Get the folder hierarchy.
583 const BookmarkNode* node = folder;
584 while (node) {
585 ExtractBookmarkNodeInformation(node, j_result_obj);
586 node = GetParentNode(node);
589 Java_BookmarksCallback_onBookmarksFolderHierarchyAvailable(
590 env, j_callback_obj, j_folder_id_obj, j_result_obj);
593 ScopedJavaLocalRef<jobject> BookmarksBridge::AddFolder(JNIEnv* env,
594 jobject obj,
595 jobject j_parent_id_obj,
596 jint index,
597 jstring j_title) {
598 DCHECK(IsLoaded());
599 long bookmark_id = JavaBookmarkIdGetId(env, j_parent_id_obj);
600 int type = JavaBookmarkIdGetType(env, j_parent_id_obj);
601 const BookmarkNode* parent = GetNodeByID(bookmark_id, type);
603 const BookmarkNode* new_node = bookmark_model_->AddFolder(
604 parent, index, base::android::ConvertJavaStringToUTF16(env, j_title));
605 if (!new_node) {
606 NOTREACHED();
607 return ScopedJavaLocalRef<jobject>();
609 ScopedJavaLocalRef<jobject> new_java_obj =
610 JavaBookmarkIdCreateBookmarkId(
611 env, new_node->id(), GetBookmarkType(new_node));
612 return new_java_obj;
615 void BookmarksBridge::DeleteBookmark(JNIEnv* env,
616 jobject obj,
617 jobject j_bookmark_id_obj) {
618 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
619 DCHECK(IsLoaded());
621 long bookmark_id = JavaBookmarkIdGetId(env, j_bookmark_id_obj);
622 int type = JavaBookmarkIdGetType(env, j_bookmark_id_obj);
623 const BookmarkNode* node = GetNodeByID(bookmark_id, type);
624 if (!IsEditable(node)) {
625 NOTREACHED();
626 return;
629 if (partner_bookmarks_shim_->IsPartnerBookmark(node)) {
630 partner_bookmarks_shim_->RemoveBookmark(node);
631 } else {
632 const BookmarkNode* parent_node = GetParentNode(node);
633 bookmark_model_->Remove(parent_node, parent_node->GetIndexOf(node));
637 void BookmarksBridge::MoveBookmark(JNIEnv* env,
638 jobject obj,
639 jobject j_bookmark_id_obj,
640 jobject j_parent_id_obj,
641 jint index) {
642 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
643 DCHECK(IsLoaded());
645 long bookmark_id = JavaBookmarkIdGetId(env, j_bookmark_id_obj);
646 int type = JavaBookmarkIdGetType(env, j_bookmark_id_obj);
647 const BookmarkNode* node = GetNodeByID(bookmark_id, type);
648 if (!IsEditable(node)) {
649 NOTREACHED();
650 return;
652 bookmark_id = JavaBookmarkIdGetId(env, j_parent_id_obj);
653 type = JavaBookmarkIdGetType(env, j_parent_id_obj);
654 const BookmarkNode* new_parent_node = GetNodeByID(bookmark_id, type);
655 bookmark_model_->Move(node, new_parent_node, index);
658 void BookmarksBridge::SearchBookmarks(JNIEnv* env,
659 jobject obj,
660 jobject j_list,
661 jstring j_query,
662 jint max_results) {
663 DCHECK(bookmark_model_->loaded());
665 std::vector<bookmarks::BookmarkMatch> results;
666 bookmark_model_->GetBookmarksMatching(
667 base::android::ConvertJavaStringToUTF16(env, j_query),
668 max_results,
669 query_parser::MatchingAlgorithm::ALWAYS_PREFIX_SEARCH,
670 &results);
671 for (const bookmarks::BookmarkMatch& match : results) {
672 const BookmarkNode* node = match.node;
673 Java_BookmarksBridge_addToBookmarkIdList(
674 env, j_list, node->id(), node->type());
678 ScopedJavaLocalRef<jobject> BookmarksBridge::AddBookmark(
679 JNIEnv* env,
680 jobject obj,
681 jobject j_parent_id_obj,
682 jint index,
683 jstring j_title,
684 jstring j_url) {
685 DCHECK(IsLoaded());
686 long bookmark_id = JavaBookmarkIdGetId(env, j_parent_id_obj);
687 int type = JavaBookmarkIdGetType(env, j_parent_id_obj);
688 const BookmarkNode* parent = GetNodeByID(bookmark_id, type);
690 const BookmarkNode* new_node = bookmark_model_->AddURL(
691 parent,
692 index,
693 base::android::ConvertJavaStringToUTF16(env, j_title),
694 GURL(base::android::ConvertJavaStringToUTF16(env, j_url)));
695 if (!new_node) {
696 NOTREACHED();
697 return ScopedJavaLocalRef<jobject>();
699 ScopedJavaLocalRef<jobject> new_java_obj =
700 JavaBookmarkIdCreateBookmarkId(
701 env, new_node->id(), GetBookmarkType(new_node));
702 return new_java_obj;
705 void BookmarksBridge::Undo(JNIEnv* env, jobject obj) {
706 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
707 DCHECK(IsLoaded());
708 BookmarkUndoService* undo_service =
709 BookmarkUndoServiceFactory::GetForProfile(profile_);
710 UndoManager* undo_manager = undo_service->undo_manager();
711 undo_manager->Undo();
714 void BookmarksBridge::StartGroupingUndos(JNIEnv* env, jobject obj) {
715 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
716 DCHECK(IsLoaded());
717 DCHECK(!grouped_bookmark_actions_.get()); // shouldn't have started already
718 grouped_bookmark_actions_.reset(
719 new bookmarks::ScopedGroupBookmarkActions(bookmark_model_));
722 void BookmarksBridge::EndGroupingUndos(JNIEnv* env, jobject obj) {
723 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
724 DCHECK(IsLoaded());
725 DCHECK(grouped_bookmark_actions_.get()); // should only call after start
726 grouped_bookmark_actions_.reset();
729 ScopedJavaLocalRef<jobject> BookmarksBridge::CreateJavaBookmark(
730 const BookmarkNode* node) {
731 JNIEnv* env = AttachCurrentThread();
733 const BookmarkNode* parent = GetParentNode(node);
734 int64 parent_id = parent ? parent->id() : -1;
736 std::string url;
737 if (node->is_url())
738 url = node->url().spec();
740 return Java_BookmarksBridge_createBookmarkItem(
741 env,
742 node->id(),
743 GetBookmarkType(node),
744 ConvertUTF16ToJavaString(env, GetTitle(node)).obj(),
745 ConvertUTF8ToJavaString(env, url).obj(),
746 node->is_folder(),
747 parent_id,
748 GetBookmarkType(parent),
749 IsEditable(node),
750 IsManaged(node));
753 void BookmarksBridge::ExtractBookmarkNodeInformation(const BookmarkNode* node,
754 jobject j_result_obj) {
755 JNIEnv* env = AttachCurrentThread();
756 if (!IsReachable(node))
757 return;
758 Java_BookmarksBridge_addToList(
759 env, j_result_obj, CreateJavaBookmark(node).obj());
762 const BookmarkNode* BookmarksBridge::GetNodeByID(long node_id, int type) {
763 const BookmarkNode* node;
764 if (type == BookmarkType::BOOKMARK_TYPE_PARTNER) {
765 node = partner_bookmarks_shim_->GetNodeByID(
766 static_cast<int64>(node_id));
767 } else {
768 node = bookmarks::GetBookmarkNodeByID(bookmark_model_,
769 static_cast<int64>(node_id));
771 return node;
774 const BookmarkNode* BookmarksBridge::GetFolderWithFallback(long folder_id,
775 int type) {
776 const BookmarkNode* folder = GetNodeByID(folder_id, type);
777 if (!folder || folder->type() == BookmarkNode::URL ||
778 !IsFolderAvailable(folder)) {
779 if (!client_->managed_node()->empty())
780 folder = client_->managed_node();
781 else
782 folder = bookmark_model_->mobile_node();
784 return folder;
787 bool BookmarksBridge::IsEditable(const BookmarkNode* node) const {
788 if (!node || (node->type() != BookmarkNode::FOLDER &&
789 node->type() != BookmarkNode::URL)) {
790 return false;
792 if (!IsEditBookmarksEnabled())
793 return false;
794 if (partner_bookmarks_shim_->IsPartnerBookmark(node))
795 return partner_bookmarks_shim_->IsEditable(node);
796 return client_->CanBeEditedByUser(node);
799 bool BookmarksBridge::IsManaged(const BookmarkNode* node) const {
800 return client_->IsDescendantOfManagedNode(node);
803 const BookmarkNode* BookmarksBridge::GetParentNode(const BookmarkNode* node) {
804 DCHECK(IsLoaded());
805 if (node == partner_bookmarks_shim_->GetPartnerBookmarksRoot()) {
806 return bookmark_model_->mobile_node();
807 } else {
808 return node->parent();
812 int BookmarksBridge::GetBookmarkType(const BookmarkNode* node) {
813 if (partner_bookmarks_shim_->IsPartnerBookmark(node))
814 return BookmarkType::BOOKMARK_TYPE_PARTNER;
815 else
816 return BookmarkType::BOOKMARK_TYPE_NORMAL;
819 base::string16 BookmarksBridge::GetTitle(const BookmarkNode* node) const {
820 if (partner_bookmarks_shim_->IsPartnerBookmark(node))
821 return partner_bookmarks_shim_->GetTitle(node);
822 return node->GetTitle();
825 bool BookmarksBridge::IsReachable(const BookmarkNode* node) const {
826 if (!partner_bookmarks_shim_->IsPartnerBookmark(node))
827 return true;
828 return partner_bookmarks_shim_->IsReachable(node);
831 bool BookmarksBridge::IsLoaded() const {
832 return (bookmark_model_->loaded() && partner_bookmarks_shim_->IsLoaded());
835 bool BookmarksBridge::IsFolderAvailable(
836 const BookmarkNode* folder) const {
837 // The managed bookmarks folder is not shown if there are no bookmarks
838 // configured via policy.
839 if (folder == client_->managed_node() && folder->empty())
840 return false;
842 SigninManager* signin = SigninManagerFactory::GetForProfile(
843 profile_->GetOriginalProfile());
844 return (folder->type() != BookmarkNode::BOOKMARK_BAR &&
845 folder->type() != BookmarkNode::OTHER_NODE) ||
846 (signin && signin->IsAuthenticated());
849 void BookmarksBridge::NotifyIfDoneLoading() {
850 if (!IsLoaded())
851 return;
852 JNIEnv* env = AttachCurrentThread();
853 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
854 if (obj.is_null())
855 return;
856 Java_BookmarksBridge_bookmarkModelLoaded(env, obj.obj());
859 // ------------- Observer-related methods ------------- //
861 void BookmarksBridge::BookmarkModelChanged() {
862 if (!IsLoaded())
863 return;
865 // Called when there are changes to the bookmark model. It is most
866 // likely changes to the partner bookmarks.
867 JNIEnv* env = AttachCurrentThread();
868 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
869 if (obj.is_null())
870 return;
871 Java_BookmarksBridge_bookmarkModelChanged(env, obj.obj());
874 void BookmarksBridge::BookmarkModelLoaded(BookmarkModel* model,
875 bool ids_reassigned) {
876 NotifyIfDoneLoading();
879 void BookmarksBridge::BookmarkModelBeingDeleted(BookmarkModel* model) {
880 if (!IsLoaded())
881 return;
883 JNIEnv* env = AttachCurrentThread();
884 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
885 if (obj.is_null())
886 return;
887 Java_BookmarksBridge_bookmarkModelDeleted(env, obj.obj());
890 void BookmarksBridge::BookmarkNodeMoved(BookmarkModel* model,
891 const BookmarkNode* old_parent,
892 int old_index,
893 const BookmarkNode* new_parent,
894 int new_index) {
895 if (!IsLoaded())
896 return;
898 JNIEnv* env = AttachCurrentThread();
899 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
900 if (obj.is_null())
901 return;
902 Java_BookmarksBridge_bookmarkNodeMoved(
903 env,
904 obj.obj(),
905 CreateJavaBookmark(old_parent).obj(),
906 old_index,
907 CreateJavaBookmark(new_parent).obj(),
908 new_index);
911 void BookmarksBridge::BookmarkNodeAdded(BookmarkModel* model,
912 const BookmarkNode* parent,
913 int index) {
914 if (!IsLoaded())
915 return;
917 JNIEnv* env = AttachCurrentThread();
918 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
919 if (obj.is_null())
920 return;
921 Java_BookmarksBridge_bookmarkNodeAdded(
922 env,
923 obj.obj(),
924 CreateJavaBookmark(parent).obj(),
925 index);
928 void BookmarksBridge::BookmarkNodeRemoved(BookmarkModel* model,
929 const BookmarkNode* parent,
930 int old_index,
931 const BookmarkNode* node,
932 const std::set<GURL>& removed_urls) {
933 if (!IsLoaded())
934 return;
936 JNIEnv* env = AttachCurrentThread();
937 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
938 if (obj.is_null())
939 return;
940 Java_BookmarksBridge_bookmarkNodeRemoved(
941 env,
942 obj.obj(),
943 CreateJavaBookmark(parent).obj(),
944 old_index,
945 CreateJavaBookmark(node).obj());
948 void BookmarksBridge::BookmarkNodeChanged(BookmarkModel* model,
949 const BookmarkNode* node) {
950 if (!IsLoaded())
951 return;
953 JNIEnv* env = AttachCurrentThread();
954 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
955 if (obj.is_null())
956 return;
957 Java_BookmarksBridge_bookmarkNodeChanged(
958 env,
959 obj.obj(),
960 CreateJavaBookmark(node).obj());
963 void BookmarksBridge::BookmarkNodeChildrenReordered(BookmarkModel* model,
964 const BookmarkNode* node) {
965 if (!IsLoaded())
966 return;
968 JNIEnv* env = AttachCurrentThread();
969 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
970 if (obj.is_null())
971 return;
972 Java_BookmarksBridge_bookmarkNodeChildrenReordered(
973 env,
974 obj.obj(),
975 CreateJavaBookmark(node).obj());
978 void BookmarksBridge::ExtensiveBookmarkChangesBeginning(BookmarkModel* model) {
979 if (!IsLoaded())
980 return;
982 JNIEnv* env = AttachCurrentThread();
983 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
984 if (obj.is_null())
985 return;
986 Java_BookmarksBridge_extensiveBookmarkChangesBeginning(env, obj.obj());
989 void BookmarksBridge::ExtensiveBookmarkChangesEnded(BookmarkModel* model) {
990 if (!IsLoaded())
991 return;
993 JNIEnv* env = AttachCurrentThread();
994 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
995 if (obj.is_null())
996 return;
997 Java_BookmarksBridge_extensiveBookmarkChangesEnded(env, obj.obj());
1000 void BookmarksBridge::PartnerShimChanged(PartnerBookmarksShim* shim) {
1001 if (!IsLoaded())
1002 return;
1004 BookmarkModelChanged();
1007 void BookmarksBridge::PartnerShimLoaded(PartnerBookmarksShim* shim) {
1008 NotifyIfDoneLoading();
1011 void BookmarksBridge::ShimBeingDeleted(PartnerBookmarksShim* shim) {
1012 partner_bookmarks_shim_ = NULL;