Change CompareString16WithCollator to take const ref collator.
[chromium-blink-merge.git] / chrome / browser / android / bookmarks / bookmarks_bridge.cc
blob9e24ca0a73395891c47d04ad0b288f8bcd86943a
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/android/bookmarks/bookmarks_bridge.h"
7 #include "base/android/jni_array.h"
8 #include "base/android/jni_string.h"
9 #include "base/containers/stack_container.h"
10 #include "base/i18n/string_compare.h"
11 #include "base/prefs/pref_service.h"
12 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
13 #include "chrome/browser/bookmarks/chrome_bookmark_client_factory.h"
14 #include "chrome/browser/bookmarks/enhanced_bookmarks_features.h"
15 #include "chrome/browser/profiles/incognito_helpers.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/profiles/profile_android.h"
18 #include "chrome/browser/signin/signin_manager_factory.h"
19 #include "chrome/browser/undo/bookmark_undo_service.h"
20 #include "chrome/browser/undo/bookmark_undo_service_factory.h"
21 #include "chrome/browser/undo/undo_manager.h"
22 #include "chrome/common/pref_names.h"
23 #include "components/bookmarks/browser/bookmark_match.h"
24 #include "components/bookmarks/browser/bookmark_model.h"
25 #include "components/bookmarks/browser/bookmark_utils.h"
26 #include "components/bookmarks/browser/scoped_group_bookmark_actions.h"
27 #include "components/bookmarks/common/android/bookmark_type.h"
28 #include "components/query_parser/query_parser.h"
29 #include "components/signin/core/browser/signin_manager.h"
30 #include "content/public/browser/browser_thread.h"
31 #include "grit/components_strings.h"
32 #include "jni/BookmarksBridge_jni.h"
33 #include "ui/base/l10n/l10n_util.h"
35 using base::android::AttachCurrentThread;
36 using base::android::ConvertUTF8ToJavaString;
37 using base::android::ConvertUTF16ToJavaString;
38 using base::android::ScopedJavaLocalRef;
39 using base::android::ScopedJavaGlobalRef;
40 using base::android::ToJavaIntArray;
41 using bookmarks::android::JavaBookmarkIdCreateBookmarkId;
42 using bookmarks::android::JavaBookmarkIdGetId;
43 using bookmarks::android::JavaBookmarkIdGetType;
44 using bookmarks::BookmarkModel;
45 using bookmarks::BookmarkNode;
46 using bookmarks::BookmarkPermanentNode;
47 using bookmarks::BookmarkType;
48 using content::BrowserThread;
50 namespace {
52 class BookmarkNodeCreationTimeCompareFunctor {
53 public:
54 bool operator()(const BookmarkNode* lhs, const BookmarkNode* rhs) {
55 return lhs->date_added().ToJavaTime() > rhs->date_added().ToJavaTime();
59 class BookmarkTitleComparer {
60 public:
61 explicit BookmarkTitleComparer(BookmarksBridge* bookmarks_bridge,
62 const icu::Collator* collator)
63 : bookmarks_bridge_(bookmarks_bridge),
64 collator_(collator) {}
66 bool operator()(const BookmarkNode* lhs, const BookmarkNode* rhs) {
67 if (collator_) {
68 return base::i18n::CompareString16WithCollator(
69 *collator_, bookmarks_bridge_->GetTitle(lhs),
70 bookmarks_bridge_->GetTitle(rhs)) == UCOL_LESS;
71 } else {
72 return lhs->GetTitle() < rhs->GetTitle();
76 private:
77 BookmarksBridge* bookmarks_bridge_; // weak
78 const icu::Collator* collator_;
81 scoped_ptr<icu::Collator> GetICUCollator() {
82 UErrorCode error = U_ZERO_ERROR;
83 scoped_ptr<icu::Collator> collator_;
84 collator_.reset(icu::Collator::createInstance(error));
85 if (U_FAILURE(error))
86 collator_.reset(NULL);
88 return collator_.Pass();
91 } // namespace
93 BookmarksBridge::BookmarksBridge(JNIEnv* env,
94 jobject obj,
95 jobject j_profile)
96 : weak_java_ref_(env, obj),
97 bookmark_model_(NULL),
98 client_(NULL),
99 partner_bookmarks_shim_(NULL) {
100 DCHECK_CURRENTLY_ON(BrowserThread::UI);
101 profile_ = ProfileAndroid::FromProfileAndroid(j_profile);
102 bookmark_model_ = BookmarkModelFactory::GetForProfile(profile_);
103 client_ = ChromeBookmarkClientFactory::GetForProfile(profile_);
105 // Registers the notifications we are interested.
106 bookmark_model_->AddObserver(this);
108 // Create the partner Bookmarks shim as early as possible (but don't attach).
109 partner_bookmarks_shim_ = PartnerBookmarksShim::BuildForBrowserContext(
110 chrome::GetBrowserContextRedirectedInIncognito(profile_));
111 partner_bookmarks_shim_->AddObserver(this);
113 NotifyIfDoneLoading();
115 // Since a sync or import could have started before this class is
116 // initialized, we need to make sure that our initial state is
117 // up to date.
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) {
129 delete this;
132 // static
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,
143 jclass clazz,
144 jobject j_profile) {
145 return IsEnhancedBookmarksEnabled();
148 static bool IsEditBookmarksEnabled(Profile* profile) {
149 return profile->GetPrefs()->GetBoolean(
150 bookmarks::prefs::kEditBookmarksEnabled);
153 static jboolean IsEditBookmarksEnabled(JNIEnv* env,
154 jclass clazz,
155 jobject j_profile) {
156 return IsEditBookmarksEnabled(ProfileAndroid::FromProfileAndroid(j_profile));
159 void BookmarksBridge::LoadEmptyPartnerBookmarkShimForTesting(JNIEnv* env,
160 jobject obj) {
161 if (partner_bookmarks_shim_->IsLoaded())
162 return;
163 partner_bookmarks_shim_->SetPartnerBookmarksRoot(
164 new BookmarkPermanentNode(0));
165 DCHECK(partner_bookmarks_shim_->IsLoaded());
168 ScopedJavaLocalRef<jobject> BookmarksBridge::GetBookmarkByID(JNIEnv* env,
169 jobject obj,
170 jlong id,
171 jint type) {
172 DCHECK(IsLoaded());
173 return CreateJavaBookmark(GetNodeByID(id, type));
176 bool BookmarksBridge::IsDoingExtensiveChanges(JNIEnv* env, jobject obj) {
177 return bookmark_model_->IsDoingExtensiveChanges();
180 void BookmarksBridge::GetPermanentNodeIDs(JNIEnv* env,
181 jobject obj,
182 jobject j_result_obj) {
183 // TODO(kkimlabs): Remove this function.
184 DCHECK(IsLoaded());
186 base::StackVector<const BookmarkNode*, 8> permanent_nodes;
188 // Save all the permanent nodes.
189 const BookmarkNode* root_node = bookmark_model_->root_node();
190 permanent_nodes->push_back(root_node);
191 for (int i = 0; i < root_node->child_count(); ++i) {
192 permanent_nodes->push_back(root_node->GetChild(i));
194 permanent_nodes->push_back(
195 partner_bookmarks_shim_->GetPartnerBookmarksRoot());
197 // Write the permanent nodes to |j_result_obj|.
198 for (base::StackVector<const BookmarkNode*, 8>::ContainerType::const_iterator
199 it = permanent_nodes->begin();
200 it != permanent_nodes->end();
201 ++it) {
202 if (*it != NULL) {
203 Java_BookmarksBridge_addToBookmarkIdList(
204 env, j_result_obj, (*it)->id(), GetBookmarkType(*it));
209 void BookmarksBridge::GetTopLevelFolderParentIDs(JNIEnv* env,
210 jobject obj,
211 jobject j_result_obj) {
212 Java_BookmarksBridge_addToBookmarkIdList(
213 env, j_result_obj, bookmark_model_->root_node()->id(),
214 GetBookmarkType(bookmark_model_->root_node()));
217 void BookmarksBridge::GetTopLevelFolderIDs(JNIEnv* env,
218 jobject obj,
219 jboolean get_special,
220 jboolean get_normal,
221 jobject j_result_obj) {
222 DCHECK(IsLoaded());
223 std::vector<const BookmarkNode*> top_level_folders;
225 if (get_special) {
226 if (client_->managed_node() &&
227 client_->managed_node()->child_count() > 0) {
228 top_level_folders.push_back(client_->managed_node());
230 if (client_->supervised_node() &&
231 client_->supervised_node()->child_count() > 0) {
232 top_level_folders.push_back(client_->supervised_node());
234 if (partner_bookmarks_shim_->HasPartnerBookmarks()
235 && IsReachable(partner_bookmarks_shim_->GetPartnerBookmarksRoot())) {
236 top_level_folders.push_back(
237 partner_bookmarks_shim_->GetPartnerBookmarksRoot());
240 std::size_t special_count = top_level_folders.size();
242 if (get_normal) {
243 DCHECK_EQ(bookmark_model_->root_node()->child_count(), 5);
245 const BookmarkNode* mobile_node = bookmark_model_->mobile_node();
246 for (int i = 0; i < mobile_node->child_count(); ++i) {
247 const BookmarkNode* node = mobile_node->GetChild(i);
248 if (node->is_folder()) {
249 top_level_folders.push_back(node);
253 const BookmarkNode* bookmark_bar_node =
254 bookmark_model_->bookmark_bar_node();
255 for (int i = 0; i < bookmark_bar_node->child_count(); ++i) {
256 const BookmarkNode* node = bookmark_bar_node->GetChild(i);
257 if (node->is_folder()) {
258 top_level_folders.push_back(node);
262 const BookmarkNode* other_node = bookmark_model_->other_node();
263 for (int i = 0; i < other_node->child_count(); ++i) {
264 const BookmarkNode* node = other_node->GetChild(i);
265 if (node->is_folder()) {
266 top_level_folders.push_back(node);
270 scoped_ptr<icu::Collator> collator = GetICUCollator();
271 std::stable_sort(top_level_folders.begin() + special_count,
272 top_level_folders.end(),
273 BookmarkTitleComparer(this, collator.get()));
276 for (std::vector<const BookmarkNode*>::const_iterator it =
277 top_level_folders.begin(); it != top_level_folders.end(); ++it) {
278 Java_BookmarksBridge_addToBookmarkIdList(env,
279 j_result_obj,
280 (*it)->id(),
281 GetBookmarkType(*it));
285 void BookmarksBridge::GetAllFoldersWithDepths(JNIEnv* env,
286 jobject obj,
287 jobject j_folders_obj,
288 jobject j_depths_obj) {
289 DCHECK(IsLoaded());
291 scoped_ptr<icu::Collator> collator = GetICUCollator();
293 // Vector to temporarily contain all child bookmarks at same level for sorting
294 std::vector<const BookmarkNode*> bookmarkList;
296 // Stack for Depth-First Search of bookmark model. It stores nodes and their
297 // heights.
298 std::stack<std::pair<const BookmarkNode*, int> > stk;
300 bookmarkList.push_back(bookmark_model_->mobile_node());
301 bookmarkList.push_back(bookmark_model_->bookmark_bar_node());
302 bookmarkList.push_back(bookmark_model_->other_node());
304 // Push all sorted top folders in stack and give them depth of 0.
305 // Note the order to push folders to stack should be opposite to the order in
306 // output.
307 for (std::vector<const BookmarkNode*>::reverse_iterator it =
308 bookmarkList.rbegin();
309 it != bookmarkList.rend();
310 ++it) {
311 stk.push(std::make_pair(*it, 0));
314 while (!stk.empty()) {
315 const BookmarkNode* node = stk.top().first;
316 int depth = stk.top().second;
317 stk.pop();
318 Java_BookmarksBridge_addToBookmarkIdListWithDepth(env,
319 j_folders_obj,
320 node->id(),
321 GetBookmarkType(node),
322 j_depths_obj,
323 depth);
324 bookmarkList.clear();
325 for (int i = 0; i < node->child_count(); ++i) {
326 const BookmarkNode* child = node->GetChild(i);
327 if (child->is_folder() && client_->CanBeEditedByUser(child))
328 bookmarkList.push_back(node->GetChild(i));
330 std::stable_sort(bookmarkList.begin(),
331 bookmarkList.end(),
332 BookmarkTitleComparer(this, collator.get()));
333 for (std::vector<const BookmarkNode*>::reverse_iterator it =
334 bookmarkList.rbegin();
335 it != bookmarkList.rend();
336 ++it) {
337 stk.push(std::make_pair(*it, depth + 1));
342 ScopedJavaLocalRef<jobject> BookmarksBridge::GetRootFolderId(JNIEnv* env,
343 jobject obj) {
344 const BookmarkNode* root_node = bookmark_model_->root_node();
345 ScopedJavaLocalRef<jobject> folder_id_obj =
346 JavaBookmarkIdCreateBookmarkId(
347 env, root_node->id(), GetBookmarkType(root_node));
348 return folder_id_obj;
351 ScopedJavaLocalRef<jobject> BookmarksBridge::GetMobileFolderId(JNIEnv* env,
352 jobject obj) {
353 const BookmarkNode* mobile_node = bookmark_model_->mobile_node();
354 ScopedJavaLocalRef<jobject> folder_id_obj =
355 JavaBookmarkIdCreateBookmarkId(
356 env, mobile_node->id(), GetBookmarkType(mobile_node));
357 return folder_id_obj;
360 ScopedJavaLocalRef<jobject> BookmarksBridge::GetOtherFolderId(JNIEnv* env,
361 jobject obj) {
362 const BookmarkNode* other_node = bookmark_model_->other_node();
363 ScopedJavaLocalRef<jobject> folder_id_obj =
364 JavaBookmarkIdCreateBookmarkId(
365 env, other_node->id(), GetBookmarkType(other_node));
366 return folder_id_obj;
369 ScopedJavaLocalRef<jobject> BookmarksBridge::GetDesktopFolderId(JNIEnv* env,
370 jobject obj) {
371 const BookmarkNode* desktop_node = bookmark_model_->bookmark_bar_node();
372 ScopedJavaLocalRef<jobject> folder_id_obj =
373 JavaBookmarkIdCreateBookmarkId(
374 env, desktop_node->id(), GetBookmarkType(desktop_node));
375 return folder_id_obj;
378 void BookmarksBridge::GetChildIDs(JNIEnv* env,
379 jobject obj,
380 jlong id,
381 jint type,
382 jboolean get_folders,
383 jboolean get_bookmarks,
384 jobject j_result_obj) {
385 DCHECK(IsLoaded());
387 const BookmarkNode* parent = GetNodeByID(id, type);
388 if (!parent->is_folder() || !IsReachable(parent))
389 return;
391 // Get the folder contents
392 for (int i = 0; i < parent->child_count(); ++i) {
393 const BookmarkNode* child = parent->GetChild(i);
394 if (!IsFolderAvailable(child) || !IsReachable(child))
395 continue;
397 if ((child->is_folder() && get_folders) ||
398 (!child->is_folder() && get_bookmarks)) {
399 Java_BookmarksBridge_addToBookmarkIdList(
400 env, j_result_obj, child->id(), GetBookmarkType(child));
404 // Partner bookmark root node is under mobile node.
405 if (parent == bookmark_model_->mobile_node() && get_folders &&
406 partner_bookmarks_shim_->HasPartnerBookmarks() &&
407 IsReachable(partner_bookmarks_shim_->GetPartnerBookmarksRoot())) {
408 Java_BookmarksBridge_addToBookmarkIdList(
409 env,
410 j_result_obj,
411 partner_bookmarks_shim_->GetPartnerBookmarksRoot()->id(),
412 BookmarkType::BOOKMARK_TYPE_PARTNER);
416 ScopedJavaLocalRef<jobject> BookmarksBridge::GetChildAt(JNIEnv* env,
417 jobject obj,
418 jlong id,
419 jint type,
420 jint index) {
421 DCHECK(IsLoaded());
423 const BookmarkNode* parent = GetNodeByID(id, type);
424 DCHECK(parent);
425 const BookmarkNode* child = parent->GetChild(index);
426 return JavaBookmarkIdCreateBookmarkId(
427 env, child->id(), GetBookmarkType(child));
430 void BookmarksBridge::GetAllBookmarkIDsOrderedByCreationDate(
431 JNIEnv* env,
432 jobject obj,
433 jobject j_result_obj) {
434 DCHECK(IsLoaded());
435 std::list<const BookmarkNode*> folders;
436 std::vector<const BookmarkNode*> result;
437 folders.push_back(bookmark_model_->root_node());
439 for (std::list<const BookmarkNode*>::iterator folder_iter = folders.begin();
440 folder_iter != folders.end(); ++folder_iter) {
441 if (*folder_iter == NULL)
442 continue;
444 std::list<const BookmarkNode*>::iterator insert_iter = folder_iter;
445 ++insert_iter;
447 for (int i = 0; i < (*folder_iter)->child_count(); ++i) {
448 const BookmarkNode* child = (*folder_iter)->GetChild(i);
449 if (!IsReachable(child) ||
450 bookmarks::IsDescendantOf(child, client_->managed_node()) ||
451 bookmarks::IsDescendantOf(child, client_->supervised_node())) {
452 continue;
455 if (child->is_folder()) {
456 insert_iter = folders.insert(insert_iter, child);
457 } else {
458 result.push_back(child);
463 std::sort(
464 result.begin(), result.end(), BookmarkNodeCreationTimeCompareFunctor());
466 for (std::vector<const BookmarkNode*>::const_iterator iter = result.begin();
467 iter != result.end();
468 ++iter) {
469 const BookmarkNode* bookmark = *iter;
470 Java_BookmarksBridge_addToBookmarkIdList(
471 env, j_result_obj, bookmark->id(), GetBookmarkType(bookmark));
475 void BookmarksBridge::SetBookmarkTitle(JNIEnv* env,
476 jobject obj,
477 jlong id,
478 jint type,
479 jstring j_title) {
480 DCHECK(IsLoaded());
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);
487 } else {
488 bookmark_model_->SetTitle(bookmark, title);
492 void BookmarksBridge::SetBookmarkUrl(JNIEnv* env,
493 jobject obj,
494 jlong id,
495 jint type,
496 jstring url) {
497 DCHECK(IsLoaded());
498 bookmark_model_->SetURL(
499 GetNodeByID(id, type),
500 GURL(base::android::ConvertJavaStringToUTF16(env, url)));
503 bool BookmarksBridge::DoesBookmarkExist(JNIEnv* env,
504 jobject obj,
505 jlong id,
506 jint type) {
507 DCHECK(IsLoaded());
508 return GetNodeByID(id, type);
511 void BookmarksBridge::GetBookmarksForFolder(JNIEnv* env,
512 jobject obj,
513 jobject j_folder_id_obj,
514 jobject j_callback_obj,
515 jobject j_result_obj) {
516 DCHECK(IsLoaded());
517 long folder_id = JavaBookmarkIdGetId(env, j_folder_id_obj);
518 int type = JavaBookmarkIdGetType(env, j_folder_id_obj);
519 const BookmarkNode* folder = GetFolderWithFallback(folder_id, type);
521 if (!folder->is_folder() || !IsReachable(folder))
522 return;
524 // Recreate the java bookmarkId object due to fallback.
525 ScopedJavaLocalRef<jobject> folder_id_obj =
526 JavaBookmarkIdCreateBookmarkId(
527 env, folder->id(), GetBookmarkType(folder));
528 j_folder_id_obj = folder_id_obj.obj();
530 // Get the folder contents.
531 for (int i = 0; i < folder->child_count(); ++i) {
532 const BookmarkNode* node = folder->GetChild(i);
533 if (!IsFolderAvailable(node))
534 continue;
535 ExtractBookmarkNodeInformation(node, j_result_obj);
538 if (folder == bookmark_model_->mobile_node() &&
539 partner_bookmarks_shim_->HasPartnerBookmarks()) {
540 ExtractBookmarkNodeInformation(
541 partner_bookmarks_shim_->GetPartnerBookmarksRoot(),
542 j_result_obj);
545 if (j_callback_obj) {
546 Java_BookmarksCallback_onBookmarksAvailable(
547 env, j_callback_obj, j_folder_id_obj, j_result_obj);
551 void BookmarksBridge::GetCurrentFolderHierarchy(JNIEnv* env,
552 jobject obj,
553 jobject j_folder_id_obj,
554 jobject j_callback_obj,
555 jobject j_result_obj) {
556 DCHECK(IsLoaded());
557 long folder_id = JavaBookmarkIdGetId(env, j_folder_id_obj);
558 int type = JavaBookmarkIdGetType(env, j_folder_id_obj);
559 const BookmarkNode* folder = GetFolderWithFallback(folder_id, type);
561 if (!folder->is_folder() || !IsReachable(folder))
562 return;
564 // Recreate the java bookmarkId object due to fallback.
565 ScopedJavaLocalRef<jobject> folder_id_obj =
566 JavaBookmarkIdCreateBookmarkId(
567 env, folder->id(), GetBookmarkType(folder));
568 j_folder_id_obj = folder_id_obj.obj();
570 // Get the folder hierarchy.
571 const BookmarkNode* node = folder;
572 while (node) {
573 ExtractBookmarkNodeInformation(node, j_result_obj);
574 node = GetParentNode(node);
577 Java_BookmarksCallback_onBookmarksFolderHierarchyAvailable(
578 env, j_callback_obj, j_folder_id_obj, j_result_obj);
581 ScopedJavaLocalRef<jobject> BookmarksBridge::AddFolder(JNIEnv* env,
582 jobject obj,
583 jobject j_parent_id_obj,
584 jint index,
585 jstring j_title) {
586 DCHECK(IsLoaded());
587 long bookmark_id = JavaBookmarkIdGetId(env, j_parent_id_obj);
588 int type = JavaBookmarkIdGetType(env, j_parent_id_obj);
589 const BookmarkNode* parent = GetNodeByID(bookmark_id, type);
591 const BookmarkNode* new_node = bookmark_model_->AddFolder(
592 parent, index, base::android::ConvertJavaStringToUTF16(env, j_title));
593 if (!new_node) {
594 NOTREACHED();
595 return ScopedJavaLocalRef<jobject>();
597 ScopedJavaLocalRef<jobject> new_java_obj =
598 JavaBookmarkIdCreateBookmarkId(
599 env, new_node->id(), GetBookmarkType(new_node));
600 return new_java_obj;
603 void BookmarksBridge::DeleteBookmark(JNIEnv* env,
604 jobject obj,
605 jobject j_bookmark_id_obj) {
606 DCHECK_CURRENTLY_ON(BrowserThread::UI);
607 DCHECK(IsLoaded());
609 long bookmark_id = JavaBookmarkIdGetId(env, j_bookmark_id_obj);
610 int type = JavaBookmarkIdGetType(env, j_bookmark_id_obj);
611 const BookmarkNode* node = GetNodeByID(bookmark_id, type);
612 if (!IsEditable(node)) {
613 NOTREACHED();
614 return;
617 if (partner_bookmarks_shim_->IsPartnerBookmark(node)) {
618 partner_bookmarks_shim_->RemoveBookmark(node);
619 } else {
620 const BookmarkNode* parent_node = GetParentNode(node);
621 bookmark_model_->Remove(parent_node, parent_node->GetIndexOf(node));
625 void BookmarksBridge::MoveBookmark(JNIEnv* env,
626 jobject obj,
627 jobject j_bookmark_id_obj,
628 jobject j_parent_id_obj,
629 jint index) {
630 DCHECK_CURRENTLY_ON(BrowserThread::UI);
631 DCHECK(IsLoaded());
633 long bookmark_id = JavaBookmarkIdGetId(env, j_bookmark_id_obj);
634 int type = JavaBookmarkIdGetType(env, j_bookmark_id_obj);
635 const BookmarkNode* node = GetNodeByID(bookmark_id, type);
636 if (!IsEditable(node)) {
637 NOTREACHED();
638 return;
640 bookmark_id = JavaBookmarkIdGetId(env, j_parent_id_obj);
641 type = JavaBookmarkIdGetType(env, j_parent_id_obj);
642 const BookmarkNode* new_parent_node = GetNodeByID(bookmark_id, type);
643 bookmark_model_->Move(node, new_parent_node, index);
646 void BookmarksBridge::SearchBookmarks(JNIEnv* env,
647 jobject obj,
648 jobject j_list,
649 jstring j_query,
650 jint max_results) {
651 DCHECK(bookmark_model_->loaded());
653 std::vector<bookmarks::BookmarkMatch> results;
654 bookmark_model_->GetBookmarksMatching(
655 base::android::ConvertJavaStringToUTF16(env, j_query),
656 max_results,
657 query_parser::MatchingAlgorithm::ALWAYS_PREFIX_SEARCH,
658 &results);
659 for (const bookmarks::BookmarkMatch& match : results) {
660 const BookmarkNode* node = match.node;
662 std::vector<int> title_match_start_positions;
663 std::vector<int> title_match_end_positions;
664 for (auto position : match.title_match_positions) {
665 title_match_start_positions.push_back(position.first);
666 title_match_end_positions.push_back(position.second);
669 std::vector<int> url_match_start_positions;
670 std::vector<int> url_match_end_positions;
671 for (auto position : match.url_match_positions) {
672 url_match_start_positions.push_back(position.first);
673 url_match_end_positions.push_back(position.second);
676 Java_BookmarksBridge_addToBookmarkMatchList(
677 env, j_list, node->id(), node->type(),
678 ToJavaIntArray(env, title_match_start_positions).obj(),
679 ToJavaIntArray(env, title_match_end_positions).obj(),
680 ToJavaIntArray(env, url_match_start_positions).obj(),
681 ToJavaIntArray(env, url_match_end_positions).obj());
685 ScopedJavaLocalRef<jobject> BookmarksBridge::AddBookmark(
686 JNIEnv* env,
687 jobject obj,
688 jobject j_parent_id_obj,
689 jint index,
690 jstring j_title,
691 jstring j_url) {
692 DCHECK(IsLoaded());
693 long bookmark_id = JavaBookmarkIdGetId(env, j_parent_id_obj);
694 int type = JavaBookmarkIdGetType(env, j_parent_id_obj);
695 const BookmarkNode* parent = GetNodeByID(bookmark_id, type);
697 const BookmarkNode* new_node = bookmark_model_->AddURL(
698 parent,
699 index,
700 base::android::ConvertJavaStringToUTF16(env, j_title),
701 GURL(base::android::ConvertJavaStringToUTF16(env, j_url)));
702 if (!new_node) {
703 NOTREACHED();
704 return ScopedJavaLocalRef<jobject>();
706 ScopedJavaLocalRef<jobject> new_java_obj =
707 JavaBookmarkIdCreateBookmarkId(
708 env, new_node->id(), GetBookmarkType(new_node));
709 return new_java_obj;
712 void BookmarksBridge::Undo(JNIEnv* env, jobject obj) {
713 DCHECK_CURRENTLY_ON(BrowserThread::UI);
714 DCHECK(IsLoaded());
715 BookmarkUndoService* undo_service =
716 BookmarkUndoServiceFactory::GetForProfile(profile_);
717 UndoManager* undo_manager = undo_service->undo_manager();
718 undo_manager->Undo();
721 void BookmarksBridge::StartGroupingUndos(JNIEnv* env, jobject obj) {
722 DCHECK_CURRENTLY_ON(BrowserThread::UI);
723 DCHECK(IsLoaded());
724 DCHECK(!grouped_bookmark_actions_.get()); // shouldn't have started already
725 grouped_bookmark_actions_.reset(
726 new bookmarks::ScopedGroupBookmarkActions(bookmark_model_));
729 void BookmarksBridge::EndGroupingUndos(JNIEnv* env, jobject obj) {
730 DCHECK_CURRENTLY_ON(BrowserThread::UI);
731 DCHECK(IsLoaded());
732 DCHECK(grouped_bookmark_actions_.get()); // should only call after start
733 grouped_bookmark_actions_.reset();
736 base::string16 BookmarksBridge::GetTitle(const BookmarkNode* node) const {
737 if (partner_bookmarks_shim_->IsPartnerBookmark(node))
738 return partner_bookmarks_shim_->GetTitle(node);
740 if (node == bookmark_model_->bookmark_bar_node()
741 && IsEnhancedBookmarksEnabled()) {
742 return l10n_util::GetStringUTF16(IDS_ENHANCED_BOOKMARK_BAR_FOLDER_NAME);
745 return node->GetTitle();
748 ScopedJavaLocalRef<jobject> BookmarksBridge::CreateJavaBookmark(
749 const BookmarkNode* node) {
750 JNIEnv* env = AttachCurrentThread();
752 const BookmarkNode* parent = GetParentNode(node);
753 int64 parent_id = parent ? parent->id() : -1;
755 std::string url;
756 if (node->is_url())
757 url = node->url().spec();
759 return Java_BookmarksBridge_createBookmarkItem(
760 env,
761 node->id(),
762 GetBookmarkType(node),
763 ConvertUTF16ToJavaString(env, GetTitle(node)).obj(),
764 ConvertUTF8ToJavaString(env, url).obj(),
765 node->is_folder(),
766 parent_id,
767 GetBookmarkType(parent),
768 IsEditable(node),
769 IsManaged(node));
772 void BookmarksBridge::ExtractBookmarkNodeInformation(const BookmarkNode* node,
773 jobject j_result_obj) {
774 JNIEnv* env = AttachCurrentThread();
775 if (!IsReachable(node))
776 return;
777 Java_BookmarksBridge_addToList(
778 env, j_result_obj, CreateJavaBookmark(node).obj());
781 const BookmarkNode* BookmarksBridge::GetNodeByID(long node_id, int type) {
782 const BookmarkNode* node;
783 if (type == BookmarkType::BOOKMARK_TYPE_PARTNER) {
784 node = partner_bookmarks_shim_->GetNodeByID(
785 static_cast<int64>(node_id));
786 } else {
787 node = bookmarks::GetBookmarkNodeByID(bookmark_model_,
788 static_cast<int64>(node_id));
790 return node;
793 const BookmarkNode* BookmarksBridge::GetFolderWithFallback(long folder_id,
794 int type) {
795 const BookmarkNode* folder = GetNodeByID(folder_id, type);
796 if (!folder || folder->type() == BookmarkNode::URL ||
797 !IsFolderAvailable(folder)) {
798 if (!client_->managed_node()->empty())
799 folder = client_->managed_node();
800 else
801 folder = bookmark_model_->mobile_node();
803 return folder;
806 bool BookmarksBridge::IsEditable(const BookmarkNode* node) const {
807 if (!node || (node->type() != BookmarkNode::FOLDER &&
808 node->type() != BookmarkNode::URL)) {
809 return false;
811 if (!IsEditBookmarksEnabled(profile_))
812 return false;
813 if (partner_bookmarks_shim_->IsPartnerBookmark(node))
814 return partner_bookmarks_shim_->IsEditable(node);
815 return client_->CanBeEditedByUser(node);
818 bool BookmarksBridge::IsManaged(const BookmarkNode* node) const {
819 return bookmarks::IsDescendantOf(node, client_->managed_node());
822 const BookmarkNode* BookmarksBridge::GetParentNode(const BookmarkNode* node) {
823 DCHECK(IsLoaded());
824 if (node == partner_bookmarks_shim_->GetPartnerBookmarksRoot()) {
825 return bookmark_model_->mobile_node();
826 } else {
827 return node->parent();
831 int BookmarksBridge::GetBookmarkType(const BookmarkNode* node) {
832 if (partner_bookmarks_shim_->IsPartnerBookmark(node))
833 return BookmarkType::BOOKMARK_TYPE_PARTNER;
834 else
835 return BookmarkType::BOOKMARK_TYPE_NORMAL;
838 bool BookmarksBridge::IsReachable(const BookmarkNode* node) const {
839 if (!partner_bookmarks_shim_->IsPartnerBookmark(node))
840 return true;
841 return partner_bookmarks_shim_->IsReachable(node);
844 bool BookmarksBridge::IsLoaded() const {
845 return (bookmark_model_->loaded() && partner_bookmarks_shim_->IsLoaded());
848 bool BookmarksBridge::IsFolderAvailable(
849 const BookmarkNode* folder) const {
850 // The managed bookmarks folder is not shown if there are no bookmarks
851 // configured via policy.
852 if (folder == client_->managed_node() && folder->empty())
853 return false;
854 // Similarly, the supervised bookmarks folder is not shown if there are no
855 // bookmarks configured by the custodian.
856 if (folder == client_->supervised_node() && folder->empty())
857 return false;
859 SigninManager* signin = SigninManagerFactory::GetForProfile(
860 profile_->GetOriginalProfile());
861 return (folder->type() != BookmarkNode::BOOKMARK_BAR &&
862 folder->type() != BookmarkNode::OTHER_NODE) ||
863 (signin && signin->IsAuthenticated());
866 void BookmarksBridge::NotifyIfDoneLoading() {
867 if (!IsLoaded())
868 return;
869 JNIEnv* env = AttachCurrentThread();
870 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
871 if (obj.is_null())
872 return;
873 Java_BookmarksBridge_bookmarkModelLoaded(env, obj.obj());
876 // ------------- Observer-related methods ------------- //
878 void BookmarksBridge::BookmarkModelChanged() {
879 if (!IsLoaded())
880 return;
882 // Called when there are changes to the bookmark model. It is most
883 // likely changes to the partner bookmarks.
884 JNIEnv* env = AttachCurrentThread();
885 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
886 if (obj.is_null())
887 return;
888 Java_BookmarksBridge_bookmarkModelChanged(env, obj.obj());
891 void BookmarksBridge::BookmarkModelLoaded(BookmarkModel* model,
892 bool ids_reassigned) {
893 NotifyIfDoneLoading();
896 void BookmarksBridge::BookmarkModelBeingDeleted(BookmarkModel* model) {
897 if (!IsLoaded())
898 return;
900 JNIEnv* env = AttachCurrentThread();
901 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
902 if (obj.is_null())
903 return;
904 Java_BookmarksBridge_bookmarkModelDeleted(env, obj.obj());
907 void BookmarksBridge::BookmarkNodeMoved(BookmarkModel* model,
908 const BookmarkNode* old_parent,
909 int old_index,
910 const BookmarkNode* new_parent,
911 int new_index) {
912 if (!IsLoaded())
913 return;
915 JNIEnv* env = AttachCurrentThread();
916 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
917 if (obj.is_null())
918 return;
919 Java_BookmarksBridge_bookmarkNodeMoved(
920 env,
921 obj.obj(),
922 CreateJavaBookmark(old_parent).obj(),
923 old_index,
924 CreateJavaBookmark(new_parent).obj(),
925 new_index);
928 void BookmarksBridge::BookmarkNodeAdded(BookmarkModel* model,
929 const BookmarkNode* parent,
930 int index) {
931 if (!IsLoaded())
932 return;
934 JNIEnv* env = AttachCurrentThread();
935 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
936 if (obj.is_null())
937 return;
938 Java_BookmarksBridge_bookmarkNodeAdded(
939 env,
940 obj.obj(),
941 CreateJavaBookmark(parent).obj(),
942 index);
945 void BookmarksBridge::BookmarkNodeRemoved(BookmarkModel* model,
946 const BookmarkNode* parent,
947 int old_index,
948 const BookmarkNode* node,
949 const std::set<GURL>& removed_urls) {
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_bookmarkNodeRemoved(
958 env,
959 obj.obj(),
960 CreateJavaBookmark(parent).obj(),
961 old_index,
962 CreateJavaBookmark(node).obj());
965 void BookmarksBridge::BookmarkAllUserNodesRemoved(
966 BookmarkModel* model,
967 const std::set<GURL>& removed_urls) {
968 if (!IsLoaded())
969 return;
971 JNIEnv* env = AttachCurrentThread();
972 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
973 if (obj.is_null())
974 return;
975 Java_BookmarksBridge_bookmarkAllUserNodesRemoved(env, obj.obj());
978 void BookmarksBridge::BookmarkNodeChanged(BookmarkModel* model,
979 const BookmarkNode* node) {
980 if (!IsLoaded())
981 return;
983 JNIEnv* env = AttachCurrentThread();
984 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
985 if (obj.is_null())
986 return;
987 Java_BookmarksBridge_bookmarkNodeChanged(
988 env,
989 obj.obj(),
990 CreateJavaBookmark(node).obj());
993 void BookmarksBridge::BookmarkNodeChildrenReordered(BookmarkModel* model,
994 const BookmarkNode* node) {
995 if (!IsLoaded())
996 return;
998 JNIEnv* env = AttachCurrentThread();
999 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
1000 if (obj.is_null())
1001 return;
1002 Java_BookmarksBridge_bookmarkNodeChildrenReordered(
1003 env,
1004 obj.obj(),
1005 CreateJavaBookmark(node).obj());
1008 void BookmarksBridge::ExtensiveBookmarkChangesBeginning(BookmarkModel* model) {
1009 if (!IsLoaded())
1010 return;
1012 JNIEnv* env = AttachCurrentThread();
1013 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
1014 if (obj.is_null())
1015 return;
1016 Java_BookmarksBridge_extensiveBookmarkChangesBeginning(env, obj.obj());
1019 void BookmarksBridge::ExtensiveBookmarkChangesEnded(BookmarkModel* model) {
1020 if (!IsLoaded())
1021 return;
1023 JNIEnv* env = AttachCurrentThread();
1024 ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
1025 if (obj.is_null())
1026 return;
1027 Java_BookmarksBridge_extensiveBookmarkChangesEnded(env, obj.obj());
1030 void BookmarksBridge::PartnerShimChanged(PartnerBookmarksShim* shim) {
1031 if (!IsLoaded())
1032 return;
1034 BookmarkModelChanged();
1037 void BookmarksBridge::PartnerShimLoaded(PartnerBookmarksShim* shim) {
1038 NotifyIfDoneLoading();
1041 void BookmarksBridge::ShimBeingDeleted(PartnerBookmarksShim* shim) {
1042 partner_bookmarks_shim_ = NULL;